【问题标题】:SQL Server deadlock clarity?SQL Server 死锁清晰?
【发布时间】:2012-09-03 20:29:03
【问题描述】:

阅读this有趣的文章后我有一些问题。

此表显示了死锁情况:

T1 对表 t_lock1 上 c1=5 的所有行持有 X 锁,而 T2 持有 X 锁定表 t_lock2 上所有 C1=1 的行。

现在这些事务中的每一个都想更新之前的行 被对方锁定。这会导致死锁。

问题 #1

  • 事务是否获得锁?我知道从表中读取是通过共享锁来完成的,而到表中是使用独占来完成的> 锁定(我说的是默认锁定设置)。

所以从这个例子看来,事务持有一个锁......它是正确的吗?

问题 #2

...T1 对表 t_lock1 上 c1=5 的所有行持有 X 锁...

  • 恕我直言,正如我所说,锁定不是每行(虽然可以进行,但作者没有提到它) - 那么他为什么说:在 C1=5 的所有行上 em> ?

【问题讨论】:

标签: sql-server sql-server-2005 deadlock


【解决方案1】:

事务是否获得锁?

没有。您执行的语句 - SELECTUPDATE 将获取锁。根据您的事务隔离级别设置,(共享)锁定(用于阅读SELECT)的持续时间将有所不同 - 仅此而已。共享锁通常只持有非常短暂的时间,而更新和排他锁会一直持有到事务结束。事务可能持有锁 - 但它不是获取锁的事务...

*...T1 在表 t_lock1...*
恕我直言,锁定不是每行(尽管可以进行,但作者没有提到它)那他为什么说:在所有 C1=5 的行上?

每行锁定 - 默认情况下。但是为什么你认为C1=5 只有一行?可能有多个(可能是数千个),UPDATE 语句将锁定所有受UPDATE 语句影响的行

【讨论】:

  • 关于持续时间:如果我开始事务并选择并且不提交,锁会永远保持吗?更新也一样?
  • @RoyiNamir:任何事务要么被提交,要么在某个时候回滚。如果您忘记提交或回滚事务,则 SQL Server 将在下次关闭时回滚它。因此,SQL Server 自动回滚事务可能需要很长时间 - 但没有任何东西会永远保持锁定 :-)
  • 所以我想我不明白共享锁的事情。如果 John 从 table 读取,同时 Paul 读取 table(都运行 select *) - 哪个部分被锁定(共享的) table?还是只有每个人读取的行? (甚至页面?)?锁在哪里? john 是否锁定了他阅读的行或他阅读的页面?如果它是共享的,我只是看不到锁在哪里......
  • @RoyiNamir:在“正常”READ COMMITTED 隔离级别下,两个读取操作都会在读取时非常短暂地锁定正在读取的行。这只是防止在有人阅读时同时更新或删除。两个共享锁是兼容的——所以即使读取操作同时发生,它们都会成功。锁在进程正在读取的行(或多行)上。默认情况下,锁总是在行级别(一个或多个行被锁定)
【解决方案2】:

对于问题 1:SQL Server 使用 U 锁读取源表行,然后更新它们,仅在符合更新条件的行上将它们转换为 X 锁。注意读取多行之间的区别,然后将它们过滤到那些被写入的行。这两组的锁定方式不同。

由于您的查询中没有选择,因此只使用 U 和 X 锁。对正在更新的表的更新查询不采用 S 锁。这是一种启发式死锁避免方案。

问题 2:可以以不同的粒度进行锁定,但对于低行数,通常是每行(这可以强制执行)。也许作者假设 C1 上有一个索引,这意味着只有 C1=1 的行需要被读取和锁定。不会触及所有其他行。

如果没有索引,SQL Server 确实会读取表的所有行,在执行此操作时对它们进行 U 锁定,然后对满足 C1=1 的那些行进行 X 锁定。作者确实提到只有 C1=1 的行是 x 锁定的。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-07-11
    • 1970-01-01
    • 2023-03-12
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多