转自:http://blog.csdn.net/eseaqyq/article/details/7795023
————————————————————————————————————————————————————
说起数据中的死锁,已经多次在笔试题目中遇到。今天特此做一个数据库死锁方面的总结,以绝后患,吼吼!
一、首先我们来看几个定义:
1.死锁
2.数据库
3.产生死锁的必要条件
- 互斥条件:指进程对所分配到的资源进行排它性使用,即在一段时间内某资源只由一个进程占用。如果此时还有其它进程请求资源,则请求者只能等待,直至占有资源的进程用毕释放。
- 请求和保持条件:指进程已经保持至少一个资源,但又提出了新的资源请求,而该资源已被其它进程占有,此时请求进程阻塞,但又对自己获得的其它资源保持不放。
- 不剥夺条件:指进程已获得的资源,在未使用完之前,不能被剥夺,只能在使用完时由自己释放。
- 环路等待条件:指在发生死锁时,必然存在一个进程——资源的环形链,即进程集合{P0,P1,P2,···,Pn}中的P0正在等待一个P1占用的资源;P1正在等待P2占用的资源,……,Pn正在等待已被P0占用的资源。
4.处理死锁的基本方式
二、数据库中的死锁是什么样的!
1.SQL server锁的机制
SQL server的所有活动都会产生锁。锁定的单元越小,就越能越能提高并发处理能力,但是管理锁的开销越大。如何找到平衡点,使并发性和性能都可接受是SQL Server的难点。
SQL Server有如下几种琐:
1、 共享锁
用于只读操作(SELECT),锁定共享的资源。共享锁不会阻止其他用户读,但是阻止其他的用户写和修改。
2、 更新锁
更新锁是一种意图锁,当一个事物已经请求共享琐后并试图请求一个独占锁的时候发生更新琐。例如当两个事物在几行数据行上都使用了共享锁,并同时试图获取独占锁以执行更新操作时,就发生了死锁:都在等待对方释放共享锁而实现独占锁。更新锁的目的是只让一个事物获得更新锁,防止这种情况的发生。
3、 独占锁(排它锁)
一次只能有一个独占锁用在一个资源上,并且阻止其他所有的锁包括共享缩。写是独占锁,可以有效的防止’脏读’
4、 意图锁
在使用共享锁和独占锁之前,使用意图锁。从表的层次上查看意图锁,以判断事物能否获得共享锁和独占锁,提高了系统的性能,不需从爷或者行上检查。
5、 计划锁
Sch-M,Sch-S。对数据库结构改变时用Sch-M,对查询进行编译时用Sch-S。这两种锁不会阻塞任何事物锁,包括独占锁。
读是共享锁,写是排他锁,先读后更新的操作是更新锁,更新锁成功并且改变了数据时更新锁升级到排他锁。
2.下面我们看下如何避免死锁
2 设置死锁超时参数为合理范围,如:3分钟-10分种;超过时间,自动放弃本次操作,避免进程悬挂;
3 所有的SP都要有错误处理(通过@error)
4 一般不要修改SQL SERVER事务的默认级别。不推荐强行加锁
5 优化程序,检查并避免死锁现象出现;
1)合理安排表访问顺序
2)在事务中尽量避免用户干预,尽量使一个事务处理的任务少些。
3)采用脏读技术。脏读由于不对被访问的表加锁,而避免了锁冲突。在客户机/服务器应用环境中,有些事务往往不允许读脏数据,但在特定的条件下,我们可以用脏读。
4)数据访问时域离散法。数据访问时域离散法是指在客户机/服务器结构中,采取各种控制手段控制对数据库或数据库中的对象访问时间段。主要通过以下方式实现: 合理安排后台事务的执行时间,采用工作流对后台事务进行统一管理。工作流在管理任务时,一方面限制同一类任务的线程数(往往限制为1个),防止资源过多占用; 另一方面合理安排不同任务执行时序、时间,尽量避免多个后台任务同时执行,另外,避免在前台交易高峰时间运行后台任务
5)数据存储空间离散法。数据存储空间离散法是指采取各种手段,将逻辑上在一个表中的数据分散到若干离散的空间上去,以便改善对表的访问性能。主要通过以下方法实现: 第一,将大表按行或列分解为若干小表; 第二,按不同的用户群分解。
6)使用尽可能低的隔离性级别。隔离性级别是指为保证数据库数据的完整性和一致性而使多用户事务隔离的程度,SQL92定义了4种隔离性级别:未提交读、提交读、可重复读和可串行。如果选择过高的隔离性级别,如可串行,虽然系统可以因实现更好隔离性而更大程度上保证数据的完整性和一致性,但各事务间冲突而死锁的机会大大增加,大大影响了系统性能。
7)使用Bound Connections。Bound connections 允许两个或多个事务连接共享事务和锁,而且任何一个事务连接要申请锁如同另外一个事务要申请锁一样,因此可以允许这些事务共享数据而不会有加锁的冲突。
8)考虑使用乐观锁定或使事务首先获得一个独占锁定。
大家看下下面的情况是否会出现死锁呢?
3.下面我们来看下下面的这个死锁问题!
- <span style="font-family:‘Microsoft YaHei‘;">-- A事务先更新table1表,然后延时30秒,再更新table2表;
- begin tran
- update table1 set A=‘aa‘ where B=‘b2‘;
- --这将在 Table1 中生成排他行锁,直到事务完成后才会释放该锁。
- waitfor delay ‘00:00:30‘;
- --进入延时
- update table2 set D=‘d5‘ where E=‘e1‘ ;
- commit tran
- -- B事务先更新table2表,然后延时10秒,再更新table1表;
- begin tran
- update table2 set D=‘d5‘ where E=‘e1‘;
- --这将在 Table2 中生成排他行锁,直到事务完成后才会释放该锁
- waitfor delay ‘00:00:10‘
- --进入延时
- update table1 set A=‘aa‘ where B=‘b2‘ ;
- commit tran</span>
若并发执行上述两个事务,A,B两事务都要等待对方释放排他锁,这样便形成了死锁。