隔离级别可序列化的事务中的死锁

时间:2020-09-28 20:15:47

标签: mysql sql transactions isolation-level pessimistic-locking

我试图了解锁定如何与隔离级别一起工作。我经历了这个question,但听不懂打击作用

在这里,我要在不同的终端机中开始两项交易,并在其中读取同一行。当我尝试更新它们时,终端会一直等待更新。除此以外,没有其他查询在运行

这是我执行的一系列步骤

conn1: START TRANSACTION;
conn1: SET SESSION TRANSACTION ISOLATION LEVEL SERIALIZABLE;
conn2: START TRANSACTION;
conn2: SET SESSION TRANSACTION ISOLATION LEVEL SERIALIZABLE;
conn1: SELECT * from users WHERE id = 1;
conn2: SELECT * from users WHERE id = 1;
conn1: UPDATE users set name = 'name' WHERE id = 1; waiting...
conn2: UPDATE users set name = 'name' WHERE id = 1; waiting...

这是我的第一个问题
在这里,我想了解为什么两个连接都在等待,如果它们是谁有锁来更新行?

如果我将上述步骤更改为

conn1: START TRANSACTION;
conn1: SET SESSION TRANSACTION ISOLATION LEVEL SERIALIZABLE;
conn2: START TRANSACTION;
conn2: SET SESSION TRANSACTION ISOLATION LEVEL SERIALIZABLE;
conn1: UPDATE users set name = 'name' WHERE id = 1;
conn2: SELECT * from users WHERE id = 1; waiting...
conn1: commit
conn2: updated results

在这种情况下,不同之处在于我可以看到conn1具有锁定,直到提交或回滚更改为止,所有其他请求都将等待,并且如果conn1已提交,则将获得更新结果

这是我的第二个问题
如果我想锁定行并且如果我想让其他连接等待(甚至用于读取),直到该锁释放(提交或回滚),或者我应该使用for update子句,这是正确的方法吗?

数据库-Mysql 5.7

1 个答案:

答案 0 :(得分:2)

SERIALIZABLE isolation level上的mysql文档说:

此级别类似于REPEATABLE READ,但是InnoDB隐式将所有普通的SELECT语句转换为SELECT ... LOCK IN SHARE MODE

关于自动提交的条款不适用于此处,因为您已明确启动事务。

这意味着在第一种情况下,两个事务都在同一记录上获得共享锁。然后,第一个事务(T1)尝试执行更新,这需要排他锁。由于T2拥有共享锁,因此无法授予该权限。然后T2尝试更新,但由于T1持有共享锁而无法更新。

是使用原子更新还是select ... for update语句来锁定记录,取决于您需要应用的应用程序逻辑。如果需要获取记录的数据并在更新记录之前进行一些复杂的计算,请使用select ... for update方法。否则,请进行原子更新。

相关问题