• 数据库的锁(转自两篇并结合)


    http://www.cnblogs.com/tenghoo/archive/2008/07/30/1256066.html
    http://www.cnblogs.com/gebagong/archive/2009/11/10/1600463.html
    锁有两种分类方法。
    (1) 从数据库系统的角度来看
    锁分为以下三种类型:
    • 独占锁(Exclusive Lock)
      独占锁锁定的资源只允许进行锁定操作的程序使用,其它任何对它的操作均不会被接受。执行数据更新命令,即INSERT、 UPDATE 或DELETE 命令时,SQL Server 会自动使用独占锁。但当对象上有其它锁存在时,无法对其加独占锁。独占锁一直到事务结束才能被释放。
    • 共享锁(Shared Lock)
      共享锁锁定的资源可以被其它用户读取,但其它用户不能修改它。在SELECT 命令执行时,SQL Server 通常会对对象进行共享锁锁定。通常加共享锁的数据页被读取完毕后,共享锁就会立即被释放。
    • 更新锁(Update Lock)
      更新锁是为了防止死锁而设立的。当SQL Server 准备更新数据时,它首先对数据对象作更共享锁锁定,这样数据将不能被修改,但可以读取。等到SQL Server 确定要进行更新数据操作时,它会自动将更新锁换为独占锁。但当对象上有其它锁存在时,无法对其作更新锁锁定。
    (2)从程序员的角度看
    锁分为以下两种类型:
    • 乐观锁(Optimistic Lock)
      乐观锁假定在处理数据时,不需要在应用程序的代码中做任何事情就可以直接在记录上加锁、即完全依靠数据库来管理锁的工作。一般情况下,当执行事务处理时SQL Server会自动对事务处理范围内更新到的表做锁定。
    • 悲观锁(Pessimistic Lock)
      悲观锁对数据库系统的自动管理不感冒,需要程序员直接管理数据或对象上的加锁处理,并负责获取、共享和放弃正在使用的数据上的任何锁。

    ---------------------------------------共享锁与独占锁都比较好理解,唯有更新锁会造成死锁---------------------------

    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(死锁)

     

    合乎自然而生生不息。。。
  • 相关阅读:
    XMLHTTP使用具体解释
    C++之EOF()
    具体解释VB中连接access数据库的几种方法
    Android中部署自己的su
    hdoj 1052 Tian Ji -- The Horse Racing【田忌赛马】 【贪心】
    【C/C++多线程编程之九】pthread读写锁
    数据结构课程设计题目十二_计算机学院学生会的打印机(优先队列)
    百度开发人员面试题(优化)
    为Windows 7的winsxs目录瘦身,谨慎。
    sonix uvc驱动的加入 RT5350支持H264
  • 原文地址:https://www.cnblogs.com/samwu/p/2181506.html
Copyright © 2020-2023  润新知