【问题标题】:Database Deadlock in SELECT FOR UPDATESELECT FOR UPDATE 中的数据库死锁
【发布时间】:2013-10-19 21:36:18
【问题描述】:

我的应用程序间歇性地陷入僵局。我的应用程序有 1 个表,例如 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);

会话 2:(用于其他业务逻辑)

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

因此,在应用程序中,两个会话都尝试更新同一行(在 ID=2 的示例行中)这种情况是意料之中的,因此我认为 SELECT .. FOR UPDATE 会有所帮助。

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

【问题讨论】:

    标签: sql sql-update database-deadlocks


    【解决方案1】:

    我假设 SELECT FOR UPDATE 将锁定该行,并且当其他会话尝试更新同一行时,它将等到会话 1 完成执行。

    正是如此。但是当您完成此行或关闭会话时,您需要关闭事务。 您的问题的可能情况如下:

    进程 1 锁定 ID=2 的行,更新它并转到 ID=1 的下一条记录(但会话和事务仍处于活动状态) 进程 2 已锁定 ID=1 的行,并将锁定 ID=2 的行(但会话和事务仍处于活动状态)

    所以进程 1 正在等待记录 ID=1 并持有记录 ID=2

    进程 2 正在等待记录 ID=2 并持有记录 ID=1

    这是一个死锁。您必须在完成记录工作后完成事务才能将其释放给其他进程。

    如果您需要在一个事务中更新多条记录,只需将它们全部锁定并在工作完成后释放。

    【讨论】:

    • 感谢 Nicolai 的快速响应。是的,你的解释是正确的。在这两个会话中,一旦处理完成,我就会提交/回滚事务,即 rs.updateRow()。在会话 1 中,我的应用程序只处理 1 行(注意:会话 1 查询可以返回多行但我只处理 1 行)。会话 2 查询将始终返回 1 行。
    • 最重要的是在两个进程中切换到其他记录之前免费(完成交易或关闭会话)记录或大量记录。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2020-11-24
    • 2010-10-31
    • 1970-01-01
    • 2019-06-13
    • 2015-10-21
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多