MSSqlserver的锁模式介绍

Posted 聆听的风声

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了MSSqlserver的锁模式介绍相关的知识,希望对你有一定的参考价值。

 

一 SQL Server 锁类型的说明

在SQL Server数据库中加锁时,除了可以对不同的资源加锁,还可以使用不同程度的加锁方式,即有多种模式,SQL Server中锁模式包括:

1.共享锁(S) 共享锁用于所以的制度数据操作。共享锁是非独占的,允许多个并发事务读取其锁定的资源。默认情况下,数据被读取后,SQL Server立刻释放共享锁。

  例如: 执行查询"SELECT * FROM dbo.Customer"时,首先锁定第一页,读取之后,释放对第一页的锁定,然后锁定第二页。这样,就允许在读操作过程中,修改未被锁定的第一页。但是,事务隔离级别链接选项设置和SELECT语句中的锁定设置都可以改变SQL Server的这种默认设置。

    执行查询"SELECT * FROM dbo.Customer WITH(HOLDLOCK)"就要求在整个查询过程中,保持对表的锁定,直到查询完成才释放锁定。

2.更新锁(U) 更新锁在修改操作的初始化阶段用来锁定可能要被修改的资源,这样可以避免使用共享锁(S)造成的死锁现象。因为使用共享锁(S)时,修改数据的操作分为两步,首先获得一个共享锁(S),读取数据,然后再将共享锁升级为排它锁(X),然后执行修改操作。这样如果同时又两个或多个事务同时对一个事务申请共享锁,在修改数据的时候,这些事务将共享锁升级为排它锁(X)。这时,这些事务都不会释放共享锁而是一直等待对方释放,这样就造成了死锁。如果一个数据在修改前直接申请更新锁(U),在数据修改的时候再升级为排它锁(X),就可以避免死锁。

3.结构锁(Sch) 执行表的数据定义语言(DDL)操作(例如添加列或除去表)时使用架构修改(Sch-M)锁。当编译查询时,使用架构稳定性(Sch-S)锁。架构稳定性锁不阻塞任何事务锁,包括排它锁。因此在编译查询时,其它事务(包括在表上有排它锁的事务)都能继续运行。但不能在表上执行DDL操作。

4.意向锁(I) 意向锁说明SQL Server有在资源的底层获得共享锁或排它锁的意向。数据库引擎使用意向锁来保护共享锁或排它锁放置在锁层次结构的底层资源上。意向锁之所以命名为意向锁,是因为在较低级别锁前可获取它们,因此会通知意向将锁放置在较低级别上。

  例如:表级的共享意向锁说明事务意图讲排它锁释放在表中的页或者行。

     意向锁有可以分为:

      共享意向锁(IS):事务意图在共享意向锁所锁定的底层资源上放置共享锁来读取数据。

      排它意向锁(IX):事务意图在共享锁锁定的资源上放置排它锁来修改数据。

      共享式排它意向锁(SIX):事务允许其他事务使用共享锁来读取顶层资源,并意图在该资源低层上放置排它锁。

      意向锁的两种用途:

      • 防止其他事务以会使较低级别的锁无效的方式修改较高级别资源。
      • 提高数据库引擎在较高的粒度级别检测锁冲突的效率。          

5.大容量更新锁(BU) 当将数据大容量复制到表,且指定了TABLOCK提示或者使用sp_tableoption设置了table lock on bulk表选项时,将使用大容量更新锁。大容量更新锁允许进程将数据并发大容量复制到同一表,同时防止其它不进行大容量复制数据的进程访问该表。

 

SQL Server使用加锁功能说明:

  • NOLOCK(不加锁):SQL Server在读取数据时不加任何锁。在这种情况下,用户可能读取到未完成事务或者回滚中的数据,即所谓的“脏数据”。仅应用于SELECT语句。    
  • HOLDLOCK(保持锁): SQL Server会将此共享锁保持至整个事务结束,而不会再途中释放。也就是说,共享锁保留到事务完成,而不是在相应的表、行、或数据页不再需要时立即释放锁。等同于SERIALIZABLE。
  • PAGLOCK(页锁): 在通常使用单个表锁的地方采用页锁。READCOMMITTED用与运行在提交读隔离级别的事务相同的锁语义执行扫描。
  • READPAST:跳过锁定行,此选项导致事务跳过由其它事务锁定的行(这些行平常会显示在结果集内),而不是阻塞该事务,使其等待其它事务释放在这些行上的锁。仅用与SELECT语句。
  • READUNCOMMITTED: 等同于NOLOCK,用与运行在可重复读隔离级别的事务相同的锁语义执行扫描。
  • ROWLOCK:使用行级锁,而不适用粒度更粗的页级锁和表级锁。SERIALIZABLE用与运行在可串行读隔离级别的事务相同的锁语义执行扫描。等同于HOLDLOCK。
  • TABLOCK: 使用表锁代替粒度更细的行级锁或页级锁。在语句结束前,SQL Server一直持有该锁。但是,如果同时制定HOLDLOCK,那么在事务结束之前,锁将被一直持有。
  • UPDLOCK: 读取表时使用更新锁,而不使用共享锁,并将锁一直保留到语句或事务的结束。UPDLOCK的优点是允许您读取数据(不阻塞其它事务)并在以后更新数据,同时确保自从上次读取数据后数据没有被更改。
  • XLOCK: 使用排它锁并一直保持到语句处理的所有数据上的事务结束时。可以使用PAGLOCK或TABLOCK指定该锁,这种情况下排它锁适用于适当级别的粒度。至于锁定多少条记录的问题,sql默认的锁定行本来就是行级别锁定的,所以你用TOP 1指定只锁定一条记录就好。 SELECT TOP 1 * FROM dbo.Customer  WITH(UPLOCK,READPAST)

二 死锁与死锁解除

1. 死锁

  使用或管理数据库都不可避免的涉及到死锁,一旦发生死锁,数据相互等待对方资源的释放,会阻止对数据的访问,严重会造成DB挂掉,当资源被锁定,无法被访问时,可以终止访问DB的那个session来达到解锁的目的(即Kill掉造成锁的那个进程)。

  在两个或多个任务中,如果每个任务锁定了其它任务试图锁定的资源,此时会造成这些任务永久阻塞,从而出现死锁。例如:

    • 事务A 获取了行1的共享锁
    • 事务B获取了行2的共享锁
    • 现在,事务A请求行2的排它锁,但在事务B完成并释放其对行2的共享锁之前被阻塞。
    • 现在,事务B请求获取行1的排它锁,但在事务A完成并释放其行1持有的共享锁之前被阻塞。        

  事务B完成之后事务A才能完成,但是事务B由事务A阻塞。该条件也称为循环依赖关系:事务A依赖于事务B,事务B通过对事务A的依赖关系关闭循环。

  除非摸个外部进程断开死锁,否则死锁中的两个事务都将无线期等待下去。SQL Server数据库引擎死锁监视器定期检查陷入死锁的任务。如果监视器检测到循环依赖关系,将选择其中一个任务作为牺牲品,然后终止其事务并提示错误。这样,其它任务就可以完成其事务。对于事务以锁雾终止的应用程序,它还可以重试该事务,但通常要等到其它一起陷入死锁的其它事务完成后执行。

2. 死锁检测

  • SQL Server数据库引擎自动检测SQL Server中的死锁循环。数据库引擎选择一个会话作为死锁牺牲品,然后终止当前事务来打断死锁。
  • 查看DMV:sys.dm_tran_locks (SELECT resource_type,resource_description,resource_associated_entity_id,request_mode,request_status,request_owner_type FROM sys.dm_tran_locks WHERE resource_type!=\'DATABASE\')  
  • SQL Server Profile能够直观的显示死锁的图形事件。

  

  死锁示例:

    第一个连接中执行:

    

BEGIN TRAN
UPDATE dbo.Customer SET NRIC=\'1000\' WHERE TransactionNumber=6
WAITFOR DELAY \'00:00:30\'
UPDATE dbo.Employee SET ts=1111 WHERE TransactionNumber=1
COMMIT

    第二个连接中执行

BEGIN TRAN
UPDATE dbo.Employee SET ts=1111 WHERE TransactionNumber=1
WAITFOR DELAY \'00:00:10\'
UPDATE dbo.Customer SET NRIC=\'1000\' WHERE TransactionNumber=6

COMMIT

  如果两个连接同时执行数据库(SQL Server2008)会自动检测到死锁,终止其中一个进程。

 

以上是关于MSSqlserver的锁模式介绍的主要内容,如果未能解决你的问题,请参考以下文章

Java多线程与并发库高级应用-工具类介绍

使用 Git 来管理 Xcode 中的代码片段

Java并发工具类StampedLock:比读写锁更快的锁

SQL(MSSQLSERVER)服务启动错误代码3414的解决方法

Solidity-ERC20代币的锁仓与释放-2

ReentrantReadWriteLock场景应用