在“SELECT FOR UPDATE”中的数据库死锁

7
我应用程序偶尔会出现死锁。我的应用程序有一个表,例如 EMPLOYEE (ID (PK), NAME, SAL),并且有2个会话。
会话1:
SELECT ID, NAME, SAL FROM EMPLOYEE WHERE SAL = (SELECT MIN(SAL) FROM 
EMPLOYEE) FOR UPDATE
Let say the query return EMPLOYEE ROW having ID=2
then application does some processing like rs.updateInt(ID_SAL, 10);

第二节:(适用于其他业务逻辑)

SELECT ID, NAME, SAL FROM EMPLOYEE WHERE ID=2 FOR UPDATE.

因此,在应用程序中,两个会话都尝试更新相同的行(例如ID为2的行)。这种情况是可以预料的,因此我认为使用SELECT .. FOR UPDATE将有所帮助。

我做错了什么吗?我假设SELECT FOR UPDATE将锁定该行,并且当其他会话尝试更新相同的行时,它将等待直到会话1完成执行。

1个回答

10
我假设SELECT FOR UPDATE会锁定行,当其他会话尝试更新相同的行时,它将等待直到第一次会话完成执行。这是确切的。但是,您需要在完成此行的操作或关闭会话时关闭事务。可能出现问题的情况如下:进程1锁定具有ID=2的行,更新该行并转到具有ID=1的下一个记录(但会话和事务仍处于活动状态); 进程2已经锁定具有ID = 1的行,并准备锁定具有ID = 2的行(但会话和事务仍然处于活动状态)。因此,进程1正在等待记录ID = 1并保留记录ID = 2;进程2正在等待记录ID = 2并保留记录ID = 1。这是死锁。您必须在与记录完成工作后完成事务以释放其供其他进程使用。如果您需要在一个事务中更新多个记录,请将它们全部一起锁定,并在完成工作后释放。

感谢Nicolai的快速回复。是的,您的解释是正确的。在两个会话中,一旦处理完成即rs.updateRow(),我都会提交/回滚事务。在Session 1中,我的应用程序仅处理1行(注意:Session 1查询可能返回多行,但我只处理1行)。而Session 2查询将始终返回1行。 - Danny Zen
在两个过程中,最重要的是在切换到其他记录之前免费记录(完整交易或关闭会话)记录或记录批量。 - Nicolai

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接