死锁
使用sqlserver profiler检测
1、新建跟踪,在跟踪属性中设置,勾选显示所有事件,其他选择去掉

2、测试实例,分别在2个新建查询中执行,其中update语句更改顺序,waitfor delay 表示等待2秒钟执行
begin tran
update T_UserDetial set Address='test2' where Name like '%s%'
waitfor delay '00:00:02'
update T_Sys_UserInfo set TS='test2' where Name like '王%' or Name like '李%'
commit tran
begin tran
update T_Sys_UserInfo set TS='test1' where Name like '王%' or Name like '李%'
waitfor delay '00:00:02'
update T_UserDetial set Address='test1' where Name like '%s%'
commit tran

3、图中x表示排它锁,打叉的表示牺牲的t-sql,另个表示优胜者,ID51执行时获取一个排它锁,然后等待2秒(waitfor delay '00:00:02'),ID52执行时获取也获取一个排它锁,然后等待2秒(waitfor delay '00:00:02');2个进程获取各自的排它锁后,2秒后就请求排它锁,然后ID52开始执行时,发现资源被ID51占用,ID51执行时发现ID52占用资源(ID51更新T_Sys_UserInfo,但是T_Sys_UserInfo存在ID52事务中,,ID52更新T_UserDetial,但是T_UserDetial在ID51事务中,所以会互相等待,进程阻塞,最终死锁)
检查到这两个进程(第一个&第二个会话)发生死锁,并对占用资源比较少的进程,列入牺牲品名单,将它终止(Kill)。通过左右椭圆形进程节点显示,可以发现已用日志最少的是左边的进程节点
SPID 52 (第一个会话)被回滚(Rollback),SPID 51 (第二个会话)执行成功

4、死锁的四个必要条件:互斥,占有并等待,不可剥夺和循环等待
SQL code 锁定提示 描述 HOLDLOCK 将共享锁保留到事务完成,而不是在相应的表、行或数据页不再需要时就立即释放锁。HOLDLOCK 等同于SERIALIZABLE。 NOLOCK 不要发出共享锁,并且不要提供排它锁。当此选项生效时,可能会读取未提交的事务或一组在读取中间回滚的页面。有可能发生脏读。仅应用于SELECT语句。 PAGLOCK 在通常使用单个表锁的地方采用页锁。 READCOMMITTED 用与运行在提交读隔离级别的事务相同的锁语义执行扫描。默认情况下,SQLServer2000在此隔离级别上操作。 READPAST 跳过锁定行。此选项导致事务跳过由其它事务锁定的行(这些行平常会显示在结果集内),而不是阻塞该事务,使其等待其它事务释放在这些行上的锁。READPAST锁提示仅适用于运行在提交读隔离级别的事务,并且只在行级锁之后读取。仅适用于SELECT语句。 READUNCOMMITTED 等同于NOLOCK。 REPEATABLEREAD 用与运行在可重复读隔离级别的事务相同的锁语义执行扫描。 ROWLOCK 使用行级锁,而不使用粒度更粗的页级锁和表级锁。 SERIALIZABLE 用与运行在可串行读隔离级别的事务相同的锁语义执行扫描。等同于HOLDLOCK。 TABLOCK 使用表锁代替粒度更细的行级锁或页级锁。在语句结束前,SQLServer一直持有该锁。但是,如果同时指定HOLDLOCK,那么在事务结束之前,锁将被一直持有。 TABLOCKX 使用表的排它锁。该锁可以防止其它事务读取或更新表,并在语句或事务结束前一直持有。 UPDLOCK 读取表时使用更新锁,而不使用共享锁,并将锁一直保留到语句或事务的结束。UPDLOCK的优点是允许您读取数据(不阻塞其它事务)并在以后更新数据,同时确保自从上次读取数据后数据没有被更改。 XLOCK 使用排它锁并一直保持到由语句处理的所有数据上的事务结束时。可以使用PAGLOCK或TABLOCK指定该锁,这种情况下排它锁适用于适当级别的粒度
(1).按同一顺序访问对象。(注:避免出现循环,降低了进程的并发执行能力)
(2).避免事务中的用户交互。(注:减少持有资源的时间,减少竞争)
(3).保持事务简短并处于一个批处理中。(注:同(2),减少持有资源的时间)

浙公网安备 33010602011771号