SQL SERVER中的两种常见死锁及解决思路
在sql server中,死锁都与一种锁有关,那就是排它锁(x锁)。由于在同一时间对同一个数据库资源只能有一个数据库进程可以拥有排它锁。因此,一旦多个进程都需要获取某个或者同一个数据库资源的排它访问权,而又被对方所阻止的时候,死锁就会出现。
第一种就是最经典的race condition思路,两个数据库进程,a和b,则a进程中修改数据表t1(假设id=100),再修改数据表t2(假设id=200);而在进程b中修改数据表t2(id=200),然后再修改数据库表t1(id=100),当两个进程在并发的情况下,就会出现a尝试获取t2的排他锁或意向排他锁,b尝试获取t1的排他锁或意向排他锁的情况,由于a已经占有了t1的排他锁,b占有了t2的排他锁,因此,进程a和进程b一直处于僵持地步,从而造成了死锁。
脚本演示:
进程1: begin tran update customer set name='test' where id=2 waitfor delay '00:00:20'; update bill set remark=remark+':test' where id=2; commit tran 进程2: begin tran update bill set remark=remark+':test' where id=2; waitfor delay '00:00:20'; update customer set name='test' where id=2; commit tran
两个进程同时执行,数据库发现存在死锁,选择一个牺牲品(victim),并直接将其kill掉:
msg 1205, level 13, state 51, line 6
transaction (process id xx) was deadlocked on lock resources with another process and has been chosen as the deadlock victim. rerun the transaction.
打开1222 trace的error log,我们发现数据库服务记录了此次死锁的最为详细的信息。
2011-01-28 23:12:59.82 spid16s resource-list 2011-01-28 23:12:59.82 spid16s keylock hobtid=72057594042515456 dbid=6 objectname=test.dbo.customer indexname=pk_customer id=lock4203a80 mode=x associatedobjectid=72057594042515456 2011-01-28 23:12:59.82 spid16s owner-list 2011-01-28 23:12:59.82 spid16s owner id=process398d48 mode=x 2011-01-28 23:12:59.82 spid16s waiter-list 2011-01-28 23:12:59.82 spid16s waiter id=process399108 mode=x requesttype=wait 2011-01-28 23:12:59.82 spid16s keylock hobtid=72057594043236352 dbid=6 objectname=test.dbo.bill indexname=pk_bill id=lock4205200 mode=x associatedobjectid=72057594043236352 2011-01-28 23:12:59.82 spid16s owner-list 2011-01-28 23:12:59.82 spid16s owner id=process399108 mode=x 2011-01-28 23:12:59.82 spid16s waiter-list 2011-01-28 23:12:59.82 spid16s waiter id=process398d48 mode=x requesttype=wait |
从这一段日志中我们可以看到,资源列表中有两个资源,每个资源都处于排它锁状态,同时每个进程的请求类型都为等待,也就是等待对方释放对自己所需资源的排它锁。
第二种死锁是由数据库底层在锁的转换时出现僵持情况造成的。例如,两个进程在各自的事务中都获取了表t中某行(id=300)的共享锁,而都需要对该行做修改,那么两个进程都要获取该行的意向排他锁,由于两个进程都拥有该行的共享锁,因此两个进程出现争端,从而产生死锁。对于这种死锁,数据库选择一个牺牲品并终止它,从而来解决死锁问题。
脚本演示
--两个或多个进程同时执行如下脚本: begin tran select * from customer where id=2; waitfor delay '00:00:05'; update customer set name=name+'a' where id=2; commit tran
这样两个进程就出现了死锁,数据库提供仲裁,选择一个牺牲品来自动解除死锁:
msg 1205, level 13, state 51, line 8
transaction (process id xx) was deadlocked on lock resources with another process and has been chosen as the deadlock victim. rerun the transaction.
打开1222 trace的error log,我仍旧摘取最后一段:
2011-01-28 23:52:48.52 spid14s resource-list 2011-01-28 23:52:48.52 spid14s keylock hobtid=72057594042515456 dbid=6 objectname=test.dbo.customer indexname=pk_customer id=lock420de80 mode=s associatedobjectid=72057594042515456 2011-01-28 23:52:48.52 spid14s owner-list 2011-01-28 23:52:48.52 spid14s owner id=process38ad48 mode=s 2011-01-28 23:52:48.52 spid14s owner id=process398f28 mode=s 2011-01-28 23:52:48.52 spid14s waiter-list 2011-01-28 23:52:48.52 spid14s waiter id=process38ad48 mode=x requesttype=convert 2011-01-28 23:52:48.52 spid14s waiter id=process398f28 mode=x requesttype=convert |
第一种死锁的requesttype为wait,而第二种死锁的requesttype为convert。
因为两种死锁产生的情形是不同的,第一种死锁是相互锁定对方需要的资源、阻止对方获取所需资源的排他访问权所造成的。第二种死锁是共同拥有同一资源的共享访问权,都在要求获取排它访问权而造成的。
从第一种死锁产生的情况看,在比较复杂的业务逻辑中,访问数据库的顺序一定要协调好,如果出现混乱,那么极有可能出现这种不必要的麻烦。
而第二种死锁似乎我们对此无能为力,因为在处理从共享锁到排它锁转换的过程由数据库来操纵。而最讨厌的是,经常会从event view中能够看到此类死锁的身影,查遍了很多地方都找不到原因。
我们仔细观察我在模拟这种死锁的sql脚本中,我在select语句之后增加了waitfor语句等待5秒钟,这是最为关键的地方,如果我去掉等待,那么我用手动是几乎不可能模拟出由共享锁升级到排它锁的死锁的,如果我再去掉select语句,那么就绝对不会有此类死锁了,一次更新就是一个更新锁(u锁),对同一个数据库资源,sql server是不会允许多于一个进程在申请同一个数据库资源时存在交叉。那么同样的道理,之所以出现这种死锁,就是由于让多于一个进程拥有了同一个数据库资源的共享锁所导致的。我不能说我的这种理解非常恰当,但是从这种死锁所产生的场景来看,只要避免共享锁过早被占,就能够解决此类死锁。
避免共享锁过早被占,其实还可以解决另外一个问题,那就是不可重复读的问题。因为共享锁过早被占,因为这在不同的进程中,数据库资源被过早的检索出来,这样就会导致不同进程的操作被覆盖,而不是累加。
那么在开发中,如何做来避免这种死锁呢?通过上面的分析,我的建议是对于数据一致性要求比较高而且操作比较频繁、复杂的数据库资源上,使用sqltransaction(isolation level=serializable),它采用的是悲观的锁定策略,在不同的进程中可以确保进程等待,而不会出现共享锁提前被占用的情况。
参考另一篇:深入浅出SQL Server中的死锁
SQL SERVER中的两种常见死锁及解决思路的更多相关文章
- 浅谈SQL Server中的三种物理连接操作
简介 在SQL Server中,我们所常见的表与表之间的Inner Join,Outer Join都会被执行引擎根据所选的列,数据上是否有索引,所选数据的选择性转化为Loop Join,Merge J ...
- SQL Server中的三种物理连接操作
来源:https://msdn.microsoft.com/zh-cn/library/dn144699.aspx 简介 在SQL Server中,我们所常见的表与表之间的Inner Join,Out ...
- 浅谈SQL Server中的三种物理连接操作(HASH JOIN MERGE JOIN NESTED LOOP)
简介 在SQL Server中,我们所常见的表与表之间的Inner Join,Outer Join都会被执行引擎根据所选的列,数据上是否有索引,所选数据的选择性转化为Loop Join,Merge J ...
- 浅谈SQL Server中的三种物理连接操作(Nested Loop Join、Merge Join、Hash Join)
简介 在SQL Server中,我们所常见的表与表之间的Inner Join,Outer Join都会被执行引擎根据所选的列,数据上是否有索引,所选数据的选择性转化为Loop Join,Merge J ...
- SQL Server 中的6种事务隔离级别简单总结
本文出处:http://www.cnblogs.com/wy123/p/7218316.html (保留出处并非什么原创作品权利,本人拙作还远远达不到,仅仅是为了链接到原文,因为后续对可能存在的一些错 ...
- SQL Server中的三种Join方式
1.测试数据准备 参考:Sql Server中的表访问方式Table Scan, Index Scan, Index Seek 这篇博客中的实验数据准备.这两篇博客使用了相同的实验数据. 2.SQ ...
- SQL Server 存储过程的几种常见写法分析,我们该用那种写法
本文出处: http://www.cnblogs.com/wy123/p/5958047.html 最近发现还有不少做开发的小伙伴,在写存储过程的时候,在参考已有的不同的写法时,往往很迷茫,不知道各种 ...
- Sql server 事务的两种用法
事务(Transaction)是并发控制的单位,是用户定义的一个操作序列.这些操作要么都做,要么都不做,是一个不可分割的工作单位. 通过事务,SQL Server能将逻辑相关的一组操作绑定在一起,以便 ...
- java web系统中时间比sql server中的日期少2天的解决办法
系统环境 jdk:1.7 数据库:sql server 2008 问题描述 升级1.7之后查询出来的日期就比数据库中的少2天,降回1.6版本的jdk就正常了. 问题原因及解决办法 国内网站有很多不靠谱 ...
随机推荐
- zabbix监控tomcat(使用jmx监控,但不使用系统自带模版)
一,zabbx使用jmx监控tomcat的原理分析 1.Zabbix-Server找Zabbix-Java-Gateway获取Java数据 2.Zabbix-Java-Gateway找Java程序(j ...
- ntohs, ntohl, htons,htonl对比
ntohs =net to host short int 16位htons=host to net short int 16位ntohl =net to host long int 32位htonl= ...
- SQL WHERE 子句
WHERE 子句 如需有条件地从表中选取数据,可将 WHERE 子句添加到 SELECT 语句. 语法 SELECT 列名称 FROM 表名称 WHERE 列 运算符 值 释意:选取 [列] 来自 [ ...
- 自动化测试基础篇--Selenium iframe定位问题
摘自https://www.cnblogs.com/sanzangTst/p/7473437.html 有时候我们在定位的途中发现一个现象,元素就在那儿,不离不去,但是我们怎么整就是定不了位,这个时候 ...
- UGUI ScrollRect 滑动
运行环境 Unity3D 5.3.7 p4 在我之前的博客中,写过一些Unity4.6的UGUI,现这篇是基于Unity 5.3的 推荐结构 推荐使用三层来组织,如下所示: ScrollRect :S ...
- python编写文件统计脚本
python编写文件统计脚本 思路:用os模块中的一些函数(os.listdir().os.path.isdir().os.path.join().os.path.abspath()等) 实现功能:显 ...
- Linux下完全删除用户
实验环境:Centos7虚拟机 首先创建一个普通用户gubeiqing. [root@localhost ~]# useradd gubeiqing [root@localhost ~]# passw ...
- MATLAB简易画图2—普通直角坐标系
MATLAB简易画图2—普通直角坐标系 本人的MATLAB版本为: 作者:凯鲁嘎吉 - 博客园 http://www.cnblogs.com/kailugaji/ 继续在“MATLAB简易画图”这篇随 ...
- 《Java大学教程》--第2章 选择
迭代(iteration).重复(repetition):三种循环* for: 重复执行固定次数* while: 重复执行不固定次数* do...while: 比while至少多一次 1.答:P47迭 ...
- MySQL高级知识(十一)——Show Profile
前言:Show Profile是mysql提供的可以用来分析当前会话中sql语句执行的资源消耗情况的工具,可用于sql调优的测量.默认情况下处于关闭状态,并保存最近15次的运行结果. 1.分析步骤 # ...