您的位置:首页 > 博客中心 > 数据库 >

sql server 锁

时间:2022-03-14 21:55

锁是一种防止在某对象执行动作的一个进程与已在该对象上执行的其他进行相冲突的机制。也就是说,如果有其他人在操作某个对象,那么你旧不能在该对象上进行操作。你能否执行操作取决于其他用户正在进行的操作。

锁的类型 意向共享锁(IS) 共享锁(S) 更新锁(U) 意向排他锁(IX) 共享意向排它锁(SIX) 排他锁(X) 意向共享锁(IS) 是 是 是 是 是 否 共享锁(S) 是 是 是 否 否 否 更新锁(U) 是 是 否 否 否 否 意向排他锁(IX) 是 否 否 是 否 否 共享意向排它锁(SIX) 是 否 否 否 否 否 排他锁(X) 否 否 否 否 否 否

  另外:

  •   Sch-S与出Sch-M以外的所有锁定模式相兼容。
  •   Sch-M和所有的锁定模式不兼容。
  •   BU只与模式稳定性锁以及其他的批量更新锁相兼容。

  有时想要在查询中或在整个事务中对锁定有更多的控制。可以通过使用优化器提示(optimizer hints)来实现这一点。

  优化器提示明确告诉SQL Server将一个锁升级为特有的层次。这些提示信息包含在将要影响的表的名称之后。

  优化器提示是一个高级主题,有经验的SQL Server开发人员会经常使用它,并且他们相当重视它。

  使用Management Studio确定锁

  查看锁的最好方式是使用Management Studio。通过使用Activity Monitor,Management Studio会以两种方式显示锁-通过processId或object。

  为了使用Management Studio显示锁,只要导航到<Server>的Activity Monitor节点,其中的<Server>是监控其活动的服务器的顶级节点。

  展开感兴趣的节点(Overview部分默认展开),可以通过滚动条查看大量度量值-包括当前系统中有效的锁。

  技术分享

  显示界面如下:   技术分享

设置隔离级别

  事务和锁之间的联系是很紧密的。默认情况下,一旦创建了任何与数据修改相关的锁,该锁定就会在整个事务期间存在。如果有一个大型事务,就意味着将在很长一段时间内阻止其他进程访问锁定的对象。这明显是有问题的。

事务有5种隔离级别:

  • READ COMMITTED
  • READ UNCOMMITTED
  • REPEATABLE READ
  • SERIALIZABLE
  • SNAPSHOT

  在这些隔离级别之间进行切换的语法也相当直观:

  SET TRANSACTION ISOLATION LEVEL < READ COMMITTED | READ UNCOMMITTED | REPEATABLE READ | SERIALIZABLE | SNAPSHOT >

  对隔离级别的修改只会影响到当前的连接-所以不必担心会影响到其他的用户。其他用户也影响不了你。

  1、READ COMMITTED

  默认情况就是这个,通过READ COMMITTED,任何创建的共享锁将在创建它们的语句完成后自动释放。也就是说,如果启动了一个事务,运行了一些语句,然后运行SELECT语句,再运行一些其他的语句,那么当SELECT语句完成的时候,与SELECT语句相关联的锁就会释放 - SQL Server并不会等到事务结束。

  动作查询(UPDATE、DELETE、INSERT)有点不同。如果事务执行了修改数据的查询,则这些锁将会在事务期间保持有效。

  通过设置READ COMMITTED这一默认隔离级别,可以确定有足够的数据完整性来防止脏读。然而,仍会发生非重复性读取和幻读。

  2、READ UNCOMMITTED

  READ UNCOMMITTED是所有隔离级别中最危险的,但是它在速度方面有最好的性能。   设置隔离级别为READ UNCOMMITTED将告诉SQL Server不要设置任何锁,也不要事先任何锁。   锁既是你的保护者,同时也是你的敌人。锁可以防止数据完整性问题,但是锁也经常妨碍或阻止你访问需要的数据。由于此锁存在脏读的危险,因此此锁只能应用于并非十分精确的环境中。

  3、REPEATABLE READ

  REPEATABLE READ会稍微地将隔离级别升级,并提供一个额外的并发保护层,这不仅能防止脏读,而且能防止非重复性读取。 防止非重复性读取是很大的优势,但是直到事务结束还保持共享锁会阻止用户访问对象,因此会影响效率。推荐使用其他的数据完整性选项,例如CHECK约束,而不是采用这个选择。   与REPEATABLE READ隔离级别等价的优化器提示是REPEATABLEREAD(除了一个空格,两者并无不同)。

  4、SERIALIZABLE

  SERIALIZABLE是堡垒级的隔离级别。除了丢失更新以外,它防止所有形式的并发问题。甚至能防止幻读。

  如果设置隔离级别为SERIALIZABLE,就意味着对事物使用的表进行的任何UPDATE、DELETE、INSERT操作绝对不满足该事务中任何语句的WHERE子句的条件。从本质上说,如果用户想执行一些事务感兴趣的事情,那么必须等到该事务完成的时候。

  SERIALIZABLE隔离级别也可以通过查询中使用SERIALIZABLE或HOLDLOCK优化器提示模拟。再次申明,类似于READ UNCOMMITTED和NOLOCK,前者不需要每次都设置,而后者需要把隔离级别设置回来。

  5、SNAPSHOT

  SNAPSHOT是最新的一种隔离级别,非常想READ COMMITTED和READ UNCOMMITTED的组合。要注意的是,SNAPSHOT默认是不可用的-只有为数据库打开了ALLOW_SNAPSHOT_ISOLATION特殊选项时,SNAPSHOT才可用。   和READ UNCOMMITED一样,SNAPSHOT并不创建任何锁,也不实现人和所。两者的主要区别是它们识别数据库中不同时段发生的更改。数据库中的更改,不管何时或是否提交,都会被运行READ UNCOMMITTED隔离级别的查询看到。而使用SNAPSHOT,只能看到在SNAPSHOT事务开始之前提交的更改。从SNAPSHOT事务一开始执行,所有查看到的数据就和在时间开始时提交的一样。

处理死锁                                                                                                            

  死锁的错误号是1205。

  如果一个锁由于另一个锁占有资源而不能完成应该做的清除资源工作,就会导致死锁;反之亦然。当发生死锁时,需要其中的一方赢得这场斗争,所以SQL Server选择一个死锁牺牲者,对死锁牺牲者的事务进行回滚,并且通过1205错误来通知发生了死锁。另外一个事务将继续正常地运行。

  1、判断死锁的方式

  每隔5秒钟,SQL Server就会检查所有当前的事务,了解他们在等待什么还未被授予的锁。然后再一次重新检查所有打开的锁请求的状态,如果先前请求中有一个还没有被授予,则它会递归地检查所有打开的事务,寻找锁定请求的循环链。如果SQL Server找到这样的村换连,则将会选择一个或更多的死锁牺牲者。

  2、选择死锁牺牲者的方式

  默认情况下,基于相关事务的"代价",选择死锁牺牲者。SQL Server将会选择回滚代价最低的事务。在一定程度上,可以使用SQL Server中的DEADLOCK_PRIORITY SET选项来重写它。

  3、避免死锁

避免死锁的常用规则

    按相同的顺序使用对象
  • 使事务尽可能简短并且在一个批处理中。
  • 尽可能使用最低的事务隔离级别。
  • 在同一事务中不允许无限度的中断。
  • 在控制环境中,使用绑定连接。

  1、按相同的顺序使用对象

  例如有两个表:Suppliers和Products。假设有两个进程将使用这两个表。进程1接受库存输入,用手头新的产品总量更新Products表,接下来用已经购买的产品总量来更新Suppliers表。进程2记录销售数据,它在Supperlier表中更新销售产品的总量,然后在Product中减少库存数量。

  如果同时运行这两个进程,那么就有可能碰到麻烦。进程1试图获取Product表上的一个排他锁。进程2将在Suppliers表上获取一个排他锁。然后进程1将试图获取Suppliers表上的一个锁,但是进程1必须等到进程2清除了现有的锁。同时进程2也在等待进程1清除现有锁。

  上面的例子是,两个进程用相反的顺序,锁住两个表,这样就很容易发生死锁。

  如果我们将进程2改成首先在Products减少库存数量,接着在Suppliers表中更新销售产品的总数量。两个进程以相同的顺序访问两张表,这样就能够减少死锁的发生。

  2、使事务尽可能简短

  保持事务的简短将不会让你付出任何的代价。在事务中放入想要的内容,把不需要的内容拿出来,就这么简单。它的原理并不复杂-事务打开的时间越长,它触及的内容就越多,那么其他一些进程想要得到正在使用的一个或者多个对象的可能性就越大。如果要保持事务简短,那么就将最小化可能引起死锁的对象的数量,还将减少锁定对象的时间。原理就如此简单。

  3、尽可能使用最低的事务隔离级别

  使用较低的隔离级别和较高的隔离级别相比,共享锁持续的时间更短,因此会减少锁的竞争。

  4、不要采用允许无限中断的事务

  当开始执行某种开放式进程时间,不要创建将一直占有资源的锁。通常,指的是用户交互,但它也可能是允许无限等待的任何进程。

热门排行

今日推荐

热门手游