Gil*_*ili 106 mysql sql sql-server transactions select-for-update
请帮我理解背后的用例SELECT ... FOR UPDATE.
问题1:以下是SELECT ... FOR UPDATE应该何时使用的一个很好的例子?
鉴于:
该应用程序希望列出所有房间及其标签,但需要区分没有标签的房间与已移除的房间.如果未使用SELECT ... FOR UPDATE,可能发生的情况是:
[id = 1][id = 1, name = 'cats'][room_id = 1, tag_id = 1]SELECT id FROM rooms;
returns [id = 1]DELETE FROM room_tags WHERE room_id = 1;DELETE FROM rooms WHERE id = 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_COMMITTED用SELECT ... FOR UPDATE?
答案应该是可移植的(不是特定于数据库的).如果那是不可能的,请解释原因.
Qua*_*noi 74
实现房间和标签之间一致性以及确保房间在删除后永远不会返回的唯一便携方式是锁定它们SELECT FOR UPDATE.
但是在某些系统中,锁定是并发控制的副作用,并且您无需FOR UPDATE显式指定即可获得相同的结果.
要解决此问题,应该使用线程1
SELECT id FROM rooms FOR UPDATE,从而防止线程2从rooms线程1完成之前删除.那是对的吗?
这取决于数据库系统正在使用的并发控制.
MyISAMin MySQL(和其他几个旧系统)确实在查询期间锁定整个表.
在SQL Server,SELECT查询将共享锁放在他们检查过的记录/页/表上,而DML查询则放置更新锁(后来被提升为独占锁或降级为共享锁).独占锁与共享锁不兼容,因此SELECT或者DELETE查询将锁定,直到另一个会话提交.
在使用数据库MVCC(如Oracle,PostgreSQL,MySQL用InnoDB),一个DML查询创建记录的副本(以一种或另一种方式),一般读者不会阻止作家,反之亦然.对于这些数据库,SELECT FOR UPDATE它会派上用场:它会锁定任何一个SELECT或DELETE查询,直到另一个会话提交,就像那样SQL Server.
当一个人应该使用
REPEATABLE_READ的事务隔离与READ_COMMITTED用SELECT ... FOR UPDATE?
通常,REPEATABLE READ不禁止幻像行(在另一个事务中出现或消失的行,而不是被修改)
在Oracle早期PostgreSQL版本中,REPEATABLE READ实际上是一个同义词SERIALIZABLE.基本上,这意味着事务在启动后看不到更改.因此,在此设置中,最后一个Thread 1查询将返回房间,就像它从未被删除一样(可能是也可能不是您想要的).如果您不想在删除后显示房间,则应使用锁定行SELECT FOR UPDATE
在InnoDB,REPEATABLE READ并且SERIALIZABLE是不同的东西:SERIALIZABLE模式中的读者在他们评估的记录上设置下一键锁定,有效地防止DML它们上的并发.因此,您不需要SELECT FOR UPDATE处于可序列化模式,但确实需要它们REPEATABLE READ或READ COMMITED.
请注意,隔离模式的标准确实规定您在查询中没有看到某些怪癖,但没有定义如何(使用锁定或使用MVCC或以其他方式).
当我说"你不需要SELECT FOR UPDATE"时,我真的应该添加"因为某些数据库引擎实现的副作用".
Col*_*art 28
简短的答案:
Q1:是的.
Q2:你使用哪个并不重要.
答案很长:
一个select ... for update意志(如它所暗示的)选择某些行,但也锁定它们,好像它们已经被当前事务更新(或者好像已经执行了身份更新).这允许您在当前事务中再次更新它们然后提交,而无需其他事务以任何方式修改这些行.
另一种看待它的方式,就好像以下两个语句是以原子方式执行的:
select * from my_table where my_condition;
update my_table set my_column = my_column where my_condition;
Run Code Online (Sandbox Code Playgroud)
由于受影响的行my_condition被锁定,因此任何其他事务都无法以任何方式修改它们,因此,事务隔离级别在这里没有区别.
另请注意,事务隔离级别与锁定无关:设置不同的隔离级别不允许您绕过事务锁定的其他事务中的锁定和更新行.
事务隔离级别保证(在不同级别)是事务正在进行时数据的一致性.
| 归档时间: |
|
| 查看次数: |
76497 次 |
| 最近记录: |