MS-SQL中的更新锁

  MSDN中,更新锁的定义是:

      更新锁(U 锁)可以防止常见的死锁。在可重复读或可序列化事务中,此事务读取数据 [获取资源(页或行)的共享锁(S 锁)],然后修改数据 [此操作要求锁转换为排他锁(X 锁)]。如果两个事务获得了资源上的共享模式锁,然后试图同时更新数据,则一个事务尝试将锁转换为排他锁(X 锁)。共享模式到排他锁的转换必  须    等待一段时间,因为一个事务的排他锁与其他事务的共享模式锁不兼容;发生锁等待。第二个事务试图获取排他锁(X 锁)以进行更新。由于两个事务都要转换为排他锁(X 锁),并且每个事务都等待另一个事务释放共享模式锁,因此发生死锁。
      若要避免这种潜在的死锁问题,请使用更新锁(U 锁)。一次只有一个事务可以获得资源的更新锁(U 锁)。如果事务修改资源,则更新锁(U 锁)转换为排他锁(X 锁)。
      对于MSDN中举的这个例子,困惑了几天。因为我一直想不明白,A事务就算在资源上有了更新锁,在更新锁转为排他锁的时候,事务B在这个资源上不是还有共享锁么?那么A事务的排他锁怎么会转成功呢?显然排他锁和共享锁是互斥的。那么还是会有死锁发生啊?怎么能够避免呢?

  找了一天的资料,经过自己试验,才发现原来是MSDN“语焉不详”。更新锁只有在事务隔离级别是Read Committed(提交读)或者它之下的时候,更新锁才能在这种情况(MSDN中的例子)下避免死锁,如果隔离级别在Read Committed(提交读)之上,比如Repeatable Read(可重复读),就算是MSDN中的那个例子,也一样会导致死锁。试验SQL如下(AdventureWorks数据库,两个级别分别开两个查询窗口,执行同样的sql,如果你的手速不够快,请把延时设高一点):

  Read Committed(提交读)级别:

      use adventureworks

   go
  set transaction isolation level Read Committed

  begin tran
  select * from DatabaseLog where DatabaseLogID = 1
  waitfor delay '00:00:05'
  update DatabaseLog set PostTime = '2006-04-26 11:48:51.160' where DatabaseLogID = 1
  commit tran

   

 

  Repeatable Read(可重复读)级别:

      use adventureworks

   go
  set transaction isolation level repeatable read
  begin tran
  select * from DatabaseLog where DatabaseLogID = 1
  waitfor delay '00:00:05'
  update DatabaseLog set PostTime = '2006-04-26 11:48:51.160' where DatabaseLogID = 1
  commit tran

   

   在提交读隔离级别,这段SQL执行同时执行,并不会产生死锁。因为在这个隔离级别,共享锁是用完就释放的。并不会等到事务结束才释放。在可重复读以上级别,共享锁会持续到事务结束,因此,就算是用更新锁中继更新数据,也会产生死锁,因为在更新锁转为排他锁的时候,还有另外一个事务的共享锁没有释放,报出错误1205(死锁)

 

 

转载于:https://www.cnblogs.com/gebagong/archive/2009/11/10/1600463.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值