当前位置: 首页 > 面试题库 >

何时使用SELECT…FOR UPDATE?

暨弘毅
2023-03-14
问题内容

请帮助我了解后面的用例SELECT ... FOR UPDATE

问题1 :以下是何时SELECT ... FOR UPDATE应使用的好例子吗?

鉴于:

  • 房间[id]
  • 标签[ID,名称]
  • room_tags [room_id,tag_id]
    • room_id和tag_id是外键

该应用程序希望列出所有房间及其标签,但是需要区分没有标签的房间和已删除的房间。如果不使用SELECT … FOR UPDATE,则可能发生以下情况:

  • 原来:
    • 房间包含 [id = 1]
    • 标签包含 [id = 1, name = 'cats']
    • room_tags包含 [room_id = 1, tag_id = 1]
  • 线程1: SELECT id FROM rooms;
    • returns [id = 1]
  • 线程2: DELETE FROM room_tags WHERE room_id = 1;
  • 线程2: DELETE FROM rooms WHERE id = 1;
  • 线程2:[提交交易]
  • 线程1: SELECT tags.name FROM room_tags, tags WHERE room_tags.tag_id = 1 AND tags.id = room_tags.tag_id;
    • 返回一个空列表

现在线程1认为会议室1没有标签,但实际上该会议室已被删除。要解决此问题,线程1应该SELECT id FROM rooms FOR UPDATE,从而防止线程2从删除rooms直到线程1完成。那是对的吗?

问题2 :一个当要使用SERIALIZABLE的事务隔离与READ_COMMITTEDSELECT ... FOR UPDATE

答案应该是可移植的(不是特定于数据库的)。如果不可能,请说明原因。


问题答案:

确保房间和标签之间的一致性并确保在删除房间后绝不返回房间的唯一可移植方法是使用锁定它们SELECT FOR UPDATE

但是,在某些系统中,锁定是并发控制的副作用,并且无需FOR UPDATE显式指定即可获得相同的结果。

要解决此问题,线程1应该SELECT id FROM rooms FOR UPDATE,从而防止线程2从删除rooms直到线程1完成。那是对的吗?

这取决于您的数据库系统正在使用的并发控制。

  • MyISAMMySQL(和其他几个老系统)则锁定整个表进行查询的时间。

  • 在中SQL ServerSELECT查询将共享锁放置在他们检查过的记录/页面/表上,而DML查询则将更新锁放置(随后将其升级为互斥或降级为共享锁)。互斥锁与共享锁不兼容,因此SELECTDELETE查询将一直锁定,直到提交另一个会话为止。

  • 在数据库在使用MVCC(如OraclePostgreSQLMySQLInnoDB),一个DML查询创建记录的副本(以一种或另一种方式),一般读者不会阻止作家,反之亦然。对于这些数据库,a SELECT FOR UPDATE会派上用场:它将锁定一个SELECT或一个DELETE查询,直到提交另一个会话为止,就像这样SQL Server做一样。

当一个人应该使用REPEATABLE_READ的事务隔离与READ_COMMITTEDSELECT ... FOR UPDATE

通常,REPEATABLE READ不禁止幻像行(在另一个事务中出现或消失的行,而不是被修改的行)

  • Oracle及早期PostgreSQL版本中,REPEATABLE READ实际上是的同义词SERIALIZABLE。基本上,这意味着事务在启动后看不到更改。因此,在此设置中,最后一个Thread 1查询将返回会议室,就好像它从未被删除过(可能是您想要的,也可能不是您想要的)。如果您不想在删除房间后显示房间,则应使用SELECT FOR UPDATE

  • InnoDBREPEATABLE READ并且SERIALIZABLE是不同的东西:读者SERIALIZABLE模式设置上,他们评估记录next-key锁定,有效防止并发DML他们。因此,您不需要SELECT FOR UPDATE处于可序列化模式,而是需要在REPEATABLE READ或中使用它们READ COMMITED

请注意,隔离模式下的标准确实规定您在查询中看不到某些怪癖,但没有定义方式(带锁或带MVCC或带或不带)。

当我说“您不需要SELECT FOR UPDATE”时,我确实应该添加“因为某些数据库引擎实现的副作用”。



 类似资料:
  • 问题内容: 大多数Hibernate关联都支持“提取”参数: 默认值为“选择”。 如何决定将哪个用于哪个关联? 我尝试将应用程序范围从“选择”全部更改为“连接”-生成的查询数量可能减少了10倍,但性能却保持不变(甚至变得稍差一点)。 谢谢。 问题答案: Join应该可以解决n + 1问题。如果您有10个父母,每个父母有10个孩子,则join将需要一个查询,而select则需要11个查询(一个对于父

  • 问题内容: 假设我有一个名为“ xml”的表,该表将XML文件存储在单列“数据”中。如何编写运行XPath并仅返回与该XPath匹配的行的MySQL查询? 问题答案: 但是,您应该注意,MySQL对XPath的支持存在局限性。 仅返回CDATA。 并非所有XPath构造都受支持。abatishchev的答案中提到的文档页面上“ XPath限制”标题下的详细信息。

  • 问题内容: 使用MySQL时是否可以以某种方式包含标头? 问题答案: 您必须自己对这些标头进行硬编码。就像是:

  • 从mytable中选择*,其中id='5'和postingdate>='2018-11-06 00:00:00'和postingdate<='2018-11-06 23:59:59'; 在开发中心控制台(或CQLSH)上运行这个查询,会给我相同的结果,而不考虑时区。我在PST和IST中都尝试过,得到了同样的结果。在执行查询之前,Cassandra是在执行PST->UTC还是IST->UTC转换?如

  • 问题内容: 如果我选择SELECT AS b且b不是表中的列,查询会创建“虚拟”列吗? 实际上,我需要将一些虚拟列合并到查询中,并将一些信息处理到查询中,以便以后可以在每个项目中使用它。 问题答案: 就像是: 这使您可以进行操作并将其显示为列。 编辑: 您还可以使用联接并将操作显示为列: