• 欢迎访问搞代码网站,推荐使用最新版火狐浏览器和Chrome浏览器访问本网站!
  • 如果您觉得本站非常有看点,那么赶紧使用Ctrl+D 收藏搞代码吧

讲解更新锁(U)与排它锁(X)的相关知识

mysql 搞代码 4年前 (2022-01-09) 30次浏览 已收录 0个评论

一直没有认真了解UPDATE操作的锁,最近在MSDN论坛上看到一个问题,询问堆表更新的死锁问题,问题很简单,有类似这样的表及数据:

CREATE TABLE dbo.tb(     c1 int,     c2 char(10),     c3 varchar(10));GODECLARE @id int;SET @id = 0;WHILE @id <5BEGIN;     SET @id = @id + 1;     INSERT dbo.tb VALUES( @id, 'b' + RIGHT(10000 + @id, 4), 'c' + RIGHT(100000 + @id, 4) );END;

在查询一中执行更新操作:

BEGIN TRANUPDATE dbo.tb SET c2 = 'xx' WHERE c1 = 2;WAITFOR DELAY '00:00:30';UPDATE dbo.tb SET c2 = 'xx' WHERE c1 = 5;ROLLBACK;

在查询一执行开始后,马上在查询二中执行下面的操作

BEGIN TRANUPDATE dbo.tb SET c2 = 'xx' WHERE c1 = 1;ROLLBACK;

为什么会出现死锁,如果条件改为 c1 = 4 则不会死锁。

开始的时候想得比较简单,死锁的表现是形成循环等待(对于两个查询而言,可以简单地认为就是在相互等待对方锁定资源的释放)。

对于这个例子而言,第一个查询更新两次,会先更新并锁定一条记录,然后等待第二个更新;但第二个查询只会更新一条记录,它要么与第一个查询冲突,无法获得锁,需要等待查询一完成,这个时候它并没有锁定什么;要么能够获得锁,完成更新。似乎不应该会出现死锁,死锁会不会是其他原因导致。

在自己的电脑上简单测试了一下,似乎也确实没有死锁。

但后面通过Profile跟踪更新操作的下锁情况才发现,自己的分析大错特错了。主要原因在于没有正确理解更新操作是如何用锁的。

在联机帮助上锁模式中有关于更新的U(更新锁)和X(排它锁)的说明

http://msdn.microsoft.com/zh-cn/library/ms175519(v=sql.105).aspx

不过说得确实挺模糊的,里面还提到了S锁,我一直以为是查询数据过程中用的S锁(也 SELECT 一样),找到满足条件的记录后用U锁,再转换为X锁做更新。

Profile(事件探查器)跟踪的结果让我知道了这是一个错

本文来源gaodai.ma#com搞##代!^码7网

误的理解,在Profile中新建一个跟踪,选择Locks中的Lock:Acquired(加锁),Lock:Acquired(释放锁)解两个事件,在筛选中设置只跟踪测试用的查询窗口对应的spid(可以执行 PRINT @@SPID获得),然后执行一个更新语句,比如 UPDATE dbo.tb SET c2 = 'xx' WHERE c1 = 3

在Profile中可以看到,对于每条记录都有加 U 锁的操作,对于不满足条件的记录,会马上释放U锁;对于满足条件的记录,最终转换为X锁。如下图所示。


搞代码网(gaodaima.com)提供的所有资源部分来自互联网,如果有侵犯您的版权或其他权益,请说明详细缘由并提供版权或权益证明然后发送到邮箱[email protected],我们会在看到邮件的第一时间内为您处理,或直接联系QQ:872152909。本网站采用BY-NC-SA协议进行授权
转载请注明原文链接:讲解更新锁(U)与排它锁(X)的相关知识
喜欢 (0)
[搞代码]
分享 (0)
发表我的评论
取消评论

表情 贴图 加粗 删除线 居中 斜体 签到

Hi,您需要填写昵称和邮箱!

  • 昵称 (必填)
  • 邮箱 (必填)
  • 网址