【问题标题】:(UPDLOCK, ROWLOCK) locks whole table even tough only 1 row is selected(UPDLOCK, ROWLOCK) 锁定整个表,即使只有 1 行被选中
【发布时间】:2024-01-07 13:34:01
【问题描述】:

在我们的 Java 应用程序中,我们使用 SQL Server 语句来暂停一些进程。

这是 SQL 语句:

SELECT * FROM MESSAGES WITH (UPDLOCK, ROWLOCK) 
WHERE MESSAGES.INTERNAL_ID IN ('6f53448f-1c47-4a58-8839-e126e81130f0');

IN 子句中的 UUID 会随着运行而变化。

这是我们用于锁定的 Java 代码:

entityManager.createNativeQuery(sqlString).getResultList()

上面的 SQL 语句只返回一行。不幸的是,似乎整个表都被锁定了。结果是所有进程都被锁定,即使没有或只有一些应该被阻止。

为什么即使我指定了UPDLOCK,整个表还是被锁定?


附加信息:

  • MESSAGES.INTERNAL_IDNVARCHAR(255),它不能为空。 否则对列没有约束。
  • 隔离级别为READ_COMMITTED

【问题讨论】:

  • 提供messages表的定义(ID是主键吗?)你的事务隔离级别是多少?
  • @MikhailLobanov 我已将请求的信息添加到问题中。

标签: java sql sql-server locking


【解决方案1】:

这是因为您的MESSAGES.INTERNAL_ID 不是密钥。一旦行被锁定,您将无法读取它并检查它的值。尝试在此列上创建一个主键。

如果不可能,请在其上创建 INDEX 并重写您的查询:

SELECT MESSAGES.INTERNAL_ID FROM MESSAGES WITH (UPDLOCK, ROWLOCK) 
WHERE MESSAGES.INTERNAL_ID IN ('6f53448f-1c47-4a58-8839-e126e81130f0');

MSDN 说:

锁定提示获取行级锁的 ROWLOCK、UPDLOCK 和 XLOCK 可能锁定索引键而不是实际的数据行。为了 例如,如果一个表有一个非聚集索引和一个 SELECT 语句 使用锁定提示由覆盖索引处理,获取锁定 在覆盖索引中的索引键上而不是在数据行上 基表。

【讨论】:

  • 谢谢!我现在使用主键进行锁定,它可以工作。
  • 还有一个问题:SELECT MESSAGES.ID 是重要部分还是 WHERE MESSAGES.ID
  • 如果您创建主键,它并不重要。 PK 通常是聚集索引(聚集索引总是覆盖)。但是如果你要创建一个非聚集索引,你应该小心选择列表。
最近更新 更多