更新后如何防止SELECT FOR UPDATE中出现死锁异常?
How to prevent Deadlock exception in SELECT FOR UPDATE after the update?
我有一个 account
table 有 1 行。
我有 2 个线程执行下一步:
第一个线程:
begin transaction;
select * from account where balance=0 for update;
UPDATE account SET balance = 10 WHERE balance=0;
// waiting here for several seconds
commit transaction;
第 2 个线程:
begin transaction;
select * from account where balance=0 for update;
commit transaction;
接下来的流程是:
1) 第一个线程开始并继续到 waiting here for several seconds
行。
2)第二个线程启动并被阻塞(逻辑上是因为第一个线程还没有释放悲观锁)。
3) 第一个线程成功提交事务。
4)第二个线程出错:ERROR 1213 (40001): Deadlock found when trying to get lock; try restarting transaction
如果没有死锁,为什么在这种情况下会出现死锁异常?我用所有 4 个事务隔离级别尝试了这个场景,并且所有隔离级别都获得了相同的错误。
问题是我的错误。所以上面的代码实际上应该可以工作。
我的问题是我在第一个线程中使用了 lock in share mode
,而在第二个线程中我使用了 for update
。我以为他们是一样的,但实际上他们不是。当我将第一个线程也更改为使用 for update
时,它们开始正常工作。
感谢 Shadow 提示使用 innodb 状态监视器检查死锁事务信息 (SHOW ENGINE INNODB STATUS;
)。
我有一个 account
table 有 1 行。
我有 2 个线程执行下一步:
第一个线程:
begin transaction;
select * from account where balance=0 for update;
UPDATE account SET balance = 10 WHERE balance=0;
// waiting here for several seconds
commit transaction;
第 2 个线程:
begin transaction;
select * from account where balance=0 for update;
commit transaction;
接下来的流程是:
1) 第一个线程开始并继续到 waiting here for several seconds
行。
2)第二个线程启动并被阻塞(逻辑上是因为第一个线程还没有释放悲观锁)。
3) 第一个线程成功提交事务。
4)第二个线程出错:ERROR 1213 (40001): Deadlock found when trying to get lock; try restarting transaction
如果没有死锁,为什么在这种情况下会出现死锁异常?我用所有 4 个事务隔离级别尝试了这个场景,并且所有隔离级别都获得了相同的错误。
问题是我的错误。所以上面的代码实际上应该可以工作。
我的问题是我在第一个线程中使用了 lock in share mode
,而在第二个线程中我使用了 for update
。我以为他们是一样的,但实际上他们不是。当我将第一个线程也更改为使用 for update
时,它们开始正常工作。
感谢 Shadow 提示使用 innodb 状态监视器检查死锁事务信息 (SHOW ENGINE INNODB STATUS;
)。