怎么样解决MSSQL产生死锁的问题

怎么样解决MSSQL产生死锁的问题,第1张

一、什么是死锁

死锁是指两个或两个以上的进程在执行过程中,因争夺资源而造成的一种互相等待的现象,若无外力作用,它们都将无法推进下去.此时称系统处于死锁状态或系统产生了死锁,这些永远在互相等的进程称为死锁进程.

二、死锁产生的四个必要条件

互斥条件:指进程对所分配到的资源进行排它性使用,即在一段时间内某资源只由一个进程占用。如果此时还有其它进程请求资源,则请求者只能等待,直至占有资源的进程用毕释放

请求和保持条件:指进程已经保持至少一个资源,但又提出了新的资源请求,而该资源已被其它进程占有,此时请求进程阻塞,但又对自己已获得的其它资源保持不放

不剥夺条件:指进程已获得的资源,在未使用完之前,不能被剥夺,只能在使用完时由自己释放

环路等待条件:指在发生死锁时,必然存在一个进程——资源的环形链,即进程集合{P0,P1,P2,···,Pn}中的P0正在等待一个P1占用的资源;P1正在等待P2占用的资源,……,Pn正在等待已被P0占用的资源

这四个条件是死锁的必要条件,只要系统发生死锁,这些条件必然成立,而只要上述条件之一不满足,就不会发生死锁。

三、 如何处理死锁

1) 锁模式

共享锁(S)

由读 *** 作创建的锁,防止在读取数据的过程中,其它事务对数据进行更新;其它事务可以并发读取数据。共享锁可以加在表、页、索引键或者数据行上。在SQL SERVER默认隔离级别下数据读取完毕后就会释放共享锁,但可以通过锁提示或设置更高的事务隔离级别改变共享锁的释放时间。

2.独占锁(X)

对资源独占的锁,一个进程独占地锁定了请求的数据源,那么别的进程无法在此数据源上获得任何类型的锁。独占锁一致持有到事务结束。

3.更新锁(U)

更新锁实际上并不是一种独立的锁,而是共享锁与独占锁的混合。当SQL SERVER执行数据修改 *** 作却首先需要搜索表以找到需要修改的资源时,会获得更新锁。

更新锁与共享锁兼容,但只有一个进程可以获取当前数据源上的更新锁,

其它进程无法获取该资源的更新锁或独占锁,更新锁的作用就好像一个序列化阀门(serialization gate),将后续申请独占锁的请求压入队列中。持有更新锁的进程能够将其转换成该资源上的独占锁。更新锁不足以用于更新数据—实际的数据修改仍需要用到独占锁。对于独占锁的序列化访问可以避免转换死锁的发生,更新锁会保留到事务结束或者当它们转换成独占锁时为止。

4. 意向锁(IX,IU,IS)

意向锁并不是独立的锁定模式,而是一种指出哪些资源已经被锁定的机制。

如果一个表页上存在独占锁,那么另一个进程就无法获得该表上的共享表锁,这种层次关系是用意向锁来实现的。进程要获得独占页锁、更新页锁或意向独占页锁,首先必须获得该表上的意向独占锁。同理,进程要获得共享行锁,必须首先获得该表的意向共享锁,以防止别的进程获得独占表锁。

5. 特殊锁模式(Sch_s,Sch_m,BU)

SQL SERVER提供3种额外的锁模式:架构稳定锁、架构修改锁、大容量更新锁。

6.转换锁(SIX,SIU,UIX)

转换锁不会由SQL SERVER 直接请求,而是从一种模式转换到另一种模式所造成的。SQL SERVER 2008支持3种类型的转换锁:SIX、SIU、UIX.其中最常见的是SIX锁,如果事务持有一个资源上的共享锁(S),然后又需要一个IX锁,此时就会出现SIX。

7.键范围锁

键范围锁是在可序列化隔离级别中锁定一定范围内数据的锁。保证在查询数据的键范围内不允许插入数据。

http://www.cnblogs.com/qiaokai/p/5344252.html

这个问题涉及几个方面:

事务处理

程序结构

程序中的锁定

1)事务处理

执行事务处理是由数据库引擎完成的。从你给出的程序片段看,这部分没有什么问题。

2)程序结构

按你说的“…… *** 作的来源不唯一,可能是后台,可能是客户自己 *** 作了什么东西,或者其他地方的来源……”。如果在程序中,从这些不同点直接对数据库 *** 作,也就是,数据库 *** 作代码散布程序中不同的地方,这样有可能导致数据库引擎死锁(如图A)。从数据库引擎角度看,当外部并发 *** 作的数量超过一定的数量就会导致死锁。从程序结构上,为了防止数据库死锁,程序结构方如图(B)。

在图B所示的结构中,数据库 *** 作的代码(包括事务处理)集中到“数据存取”模块并通过这个这个模块和数据引擎交互。显然,结构B将程序与数据引擎交互降到了最低(1个)

3)程序中的锁定

在结构B中,如果在“数据存取”模块中使用lock机制,强制将来自程序不同地点数据库 *** 作序列化,这样就可以有效防止数据库死锁了。

1\x0d\x0a如何锁一个表的某一行\x0d\x0a\x0d\x0aSETTRANSACTION\x0d\x0aISOLATIONLEVELREADUNCOMMITTED\x0d\x0a\x0d\x0aSELECT*FROMtableROWLOCKWHEREid=1\x0d\x0a\x0d\x0a2锁定数据库的一个表\x0d\x0a\x0d\x0aSELECT*FROMtableWITH(HOLDLOCK)\x0d\x0a\x0d\x0a加锁语句:\x0d\x0asybase:\x0d\x0aupdate表setcol1=col1where1=0\x0d\x0a\x0d\x0aMSSQL:\x0d\x0aselectcol1from表(tablockx)\x0d\x0awhere\x0d\x0a1=0\x0d\x0a\x0d\x0aoracle:\x0d\x0aLOCKTABLE表INEXCLUSIVEMODE;\x0d\x0a\x0d\x0a加锁后其它人不可 *** 作,直到加锁用户解锁,用commit或rollback解锁\x0d\x0a\x0d\x0a几个例子帮助大家加深印象\x0d\x0a\x0d\x0a设table1(A,B,C)\x0d\x0aABC\x0d\x0aa1b1c1\x0d\x0aa2b2c2\x0d\x0aa3b3c3\x0d\x0a\x0d\x0a1)排它锁\x0d\x0a新建两个连接\x0d\x0a在第一个连接中执行以下语句\x0d\x0abegintran\x0d\x0aupdatetable1\x0d\x0a\x0d\x0aset\x0d\x0aA='aa'\x0d\x0awhereB='b2'\x0d\x0awaitfordelay\x0d\x0a'00:00:30'--等待30秒\x0d\x0acommittran\x0d\x0a\x0d\x0a在第二个连接中执行以下语句\x0d\x0abegintran\x0d\x0aselect*fromtable1\x0d\x0a\x0d\x0awhereB='b2'\x0d\x0acommittran\x0d\x0a\x0d\x0a若同时执行上述两个语句,则select查询必须等待update执行完毕才能执行即要等待30秒\x0d\x0a\x0d\x0a2)共享锁\x0d\x0a在第一个连接中执行以下语句\x0d\x0abegintran\x0d\x0aselect*fromtable1\x0d\x0aholdlock\x0d\x0a-holdlock人为加锁\x0d\x0awhereB='b2'\x0d\x0awaitfordelay\x0d\x0a'00:00:30'--等待30秒\x0d\x0acommittran\x0d\x0a\x0d\x0a在第二个连接中执行以下语句\x0d\x0abegintran\x0d\x0aselectA,C\x0d\x0afrom\x0d\x0atable1\x0d\x0awhereB='b2'\x0d\x0aupdatetable1\x0d\x0a\x0d\x0aset\x0d\x0aA='aa'\x0d\x0awhereB='b2'\x0d\x0acommittran\x0d\x0a\x0d\x0a若同时执行上述两个语句,则第二个连接中的select查询可以执行\x0d\x0a而update必须等待第一个事务释放共享锁转为排它锁后才能执行\x0d\x0a即要等待30秒\x0d\x0a\x0d\x0a3)死锁\x0d\x0a增设table2(D,E)\x0d\x0aDE\x0d\x0ad1e1\x0d\x0ad2e2\x0d\x0a\x0d\x0a在第一个连接中执行以下语句\x0d\x0abegintran\x0d\x0aupdatetable1\x0d\x0a\x0d\x0aset\x0d\x0aA='aa'\x0d\x0awhereB='b2'\x0d\x0awaitfordelay\x0d\x0a'00:00:30'\x0d\x0aupdatetable2\x0d\x0a\x0d\x0aset\x0d\x0aD='d5'\x0d\x0awhereE='e1'\x0d\x0acommittran\x0d\x0a\x0d\x0a在第二个连接中执行以下语句\x0d\x0abegintran\x0d\x0aupdatetable2\x0d\x0a\x0d\x0aset\x0d\x0aD='d5'\x0d\x0awhereE='e1'\x0d\x0awaitfordelay\x0d\x0a'00:00:10'\x0d\x0aupdatetable1\x0d\x0a\x0d\x0aset\x0d\x0aA='aa'\x0d\x0awhereB='b2'\x0d\x0acommittran\x0d\x0a\x0d\x0a同时执行,系统会检测出死锁,并中止进程\x0d\x0a\x0d\x0a补充一点:\x0d\x0aSqlServer2000支持的表级锁定提示\x0d\x0a\x0d\x0aHOLDLOCK持有共享锁,直到整个事务完成,应该在被锁对象不需要时立即释放,等于SERIALIZABLE事务隔离级别\x0d\x0a\x0d\x0aNOLOCK语句执行时不发出共享锁,允许脏读,等于READ\x0d\x0aUNCOMMITTED事务隔离级别\x0d\x0a\x0d\x0aPAGLOCK在使用一个表锁的地方用多个页锁\x0d\x0a\x0d\x0aREADPAST让sql\x0d\x0aserver跳过任何锁定行,执行事务,适用于READUNCOMMITTED事务隔离级别只跳过RID锁,不跳过页,区域和表锁\x0d\x0a\x0d\x0aROWLOCK\x0d\x0a强制使用行锁\x0d\x0a\x0d\x0aTABLOCKX强制使用独占表级锁,这个锁在事务期间阻止任何其他事务使用这个表\x0d\x0a\x0d\x0aUPLOCK\x0d\x0a强制在读表时使用更新而不用共享锁\x0d\x0a\x0d\x0a应用程序锁:\x0d\x0a应用程序锁就是客户端代码生成的锁,而不是sqlserver本身生成的锁\x0d\x0a\x0d\x0a处理应用程序锁的两个过程\x0d\x0a\x0d\x0asp_getapplock锁定应用程序资源\x0d\x0a\x0d\x0asp_releaseapplock\x0d\x0a为应用程序资源解锁\x0d\x0a\x0d\x0a注意:锁定数据库的一个表的区别\x0d\x0a\x0d\x0aSELECT*FROMtableWITH(HOLDLOCK)\x0d\x0a其他事务可以读取表,但不能更新删除\x0d\x0a\x0d\x0aSELECT*FROMtableWITH(TABLOCKX)\x0d\x0a其他事务不能读取表,更新和删除\x0d\x0a\x0d\x0a1\x0d\x0a如何锁一个表的某一行\x0d\x0a/*\x0d\x0a测试环境:windows2Kserver+Mssql2000\x0d\x0a\x0d\x0a所有功能都进行测试过,并有相应的结果集,如果有什么疑义在论坛跟帖\x0d\x0a\x0d\x0a关于版权的说明:部分资料来自互联网,如有不当请联系版主,版主会在第一时间处理。\x0d\x0a\x0d\x0a功能:sql遍历文件夹下的文本文件名,当然你修改部分代码后可以完成各种文件的列表。\x0d\x0a*/\x0d\x0a\x0d\x0aA\x0d\x0a连接中执行\x0d\x0a\x0d\x0aSETTRANSACTION\x0d\x0aISOLATIONLEVELREPEATABLE\x0d\x0aREAD\x0d\x0a\x0d\x0abegintran\x0d\x0a\x0d\x0aselect*fromtablename\x0d\x0awith\x0d\x0a(rowlock)whereid=3\x0d\x0a\x0d\x0awaitfordelay'00:00:05'\x0d\x0a\x0d\x0acommittran\x0d\x0a\x0d\x0aB连接中如果执行\x0d\x0a\x0d\x0aupdatetablenameset\x0d\x0acolname='10'whereid=3\x0d\x0a--则要等待5秒\x0d\x0a\x0d\x0aupdatetablename\x0d\x0aset\x0d\x0acolname='10'whereid3\x0d\x0a--可立即执行\x0d\x0a\x0d\x0a2\x0d\x0a锁定数据库的一个表\x0d\x0a\x0d\x0aSELECT*FROMtableWITH(HOLDLOCK)\x0d\x0a\x0d\x0a注意:锁定数据库的一个表的区别\x0d\x0a\x0d\x0aSELECT*FROMtableWITH(HOLDLOCK)\x0d\x0a\x0d\x0a其他事务可以读取表,但不能更新删除\x0d\x0a\x0d\x0aSELECT*FROMtableWITH(TABLOCKX)\x0d\x0a\x0d\x0a其他事务不能读取表,更新和删除


欢迎分享,转载请注明来源:内存溢出

原文地址: http://outofmemory.cn/sjk/10056415.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2023-05-04
下一篇 2023-05-04

发表评论

登录后才能评论

评论列表(0条)

保存