详解SQL死锁检测的方法
sqlserver中的死锁是指进程之间互相永久阻塞的状态,下文就将为您介绍如何检测sqlserver死锁,希望对您有所帮助。
死锁(deadlock)指进程之间互相永久阻塞的状态,SQL可以检测到死锁,并选择终止其中一个事务以干预sqlserver死锁状态。
第一步:首先创建两个测试表,表goods_sort和goods
表goods_sort:创建并写入测试数据
IFEXISTS(SELECTnameFROMsysobjectsWHEREname='goods_sort'ANDxtype='U') DROPTABLEdbo.goods_sort --创建商品分类表 CREATETABLEdbo.goods_sort( iSortIDintNOTNULL CONSTRAINTPK_iSortIDPRIMARYKEY IDENTITY(1001,1), sSortNameNVARCHAR(20)NOTNULL ) GO INSERTINTOdbo.goods_sortVALUES('服饰') INSERTINTOdbo.goods_sortVALUES('女包') INSERTINTOdbo.goods_sortVALUES('鞋子') INSERTINTOdbo.goods_sortVALUES('首饰') INSERTINTOdbo.goods_sortVALUES('美容') GO
表goods:创建并写入测试数据
IFEXISTS(SELECTnameFROMsysobjectsWHEREname='goods'ANDxtype='U') DROPTABLEdbo.goods; --创建商品表 CREATETABLEdbo.goods( iIDintNOTNULL CONSTRAINTPK_iIDPRIMARYKEY IDENTITY(1,1), iGoodsIDvarchar(20)NOTNULL, sGoodsNamenvarchar(100)NOTNULL, iGoodTotalintNOTNULL CONSTRAINTDF_iGoodTotalDEFAULT(0), iPriceintNOTNULL CONSTRAINTDF_iPriceDEFAULT(0), iPriceTotalintNOTNULL, iSortIDintNOTNULL, tAddDatesmalldatetimeNOTNULL CONSTRAINTDF_tAddDateDEFAULTgetdate() ) GO INSERTINTOdbo.goods (iGoodsID,sGoodsName,iGoodTotal,iPrice,iPriceTotal,iSortID) VALUES('YR6001','瘦身羽绒服',20,200,4000,1001) INSERTINTOdbo.goods (iGoodsID,sGoodsName,iGoodTotal,iPrice,iPriceTotal,iSortID) VALUES('YR6002','加厚羽绒服',20,300,6000,1001) INSERTINTOdbo.goods (iGoodsID,sGoodsName,iGoodTotal,iPrice,iPriceTotal,iSortID) VALUES('BB7001','小黄牛皮马鞍包',30,100,3000,1002) INSERTINTOdbo.goods (iGoodsID,sGoodsName,iGoodTotal,iPrice,iPriceTotal,iSortID) VALUES('BB7002','十字绣流苏包',50,150,7500,1002) GO
第二步:创建两个会产生死锁的事务
事务1:
SETNOCOUNTON; SETXACT_ABORTON; GO --使用TRY-CATCH,使代码发生错误也继续运行 BEGINTRY BEGINTRAN UPDATEdbo.goods_sortSETsSortName='女鞋'WHEREiSortID=1003; WAITFORDELAY'00:00:05'; UPDATEdbo.goodsSETsGoodsName='胖子羽绒服'WHEREiID=2; COMMITTRAN ENDTRY BEGINCATCH IF(XACT_STATE()=-1) ROLLBACKTRAN; --ERROR_NUMBER()值为1205则表示发生了死锁 IF(ERROR_NUMBER()=1205) PRINT'事务1发生了死锁' --写SQLServer日志或者返回错误给应用程序 ENDCATCH SELECTiID,sGoodsNameFROMdbo.goodsWHEREiID=2; SELECTiSortID,sSortNameFROMdbo.goods_sortWHEREiSortID=1003; GO
事务2:
SETNOCOUNTON; SETXACT_ABORTON; GO --使用TRY-CATCH,使代码发生错误也继续运行 BEGINTRY BEGINTRAN UPDATEdbo.goodsSETsGoodsName='瘦子羽绒服'WHEREiID=2; WAITFORDELAY'00:00:05'; UPDATEdbo.goods_sortSETsSortName='男鞋'WHEREiSortID=1003; COMMITTRAN ENDTRY BEGINCATCH IF(XACT_STATE()=-1) ROLLBACKTRAN; --ERROR_NUMBER()值为1205则表示发生了死锁 IF(ERROR_NUMBER()=1205) PRINT'事务2发生了死锁' --写SQLServer日志或者返回错误给应用程序 ENDCATCH SELECTiID,sGoodsNameFROMdbo.goodsWHEREiID=2; SELECTiSortID,sSortNameFROMdbo.goods_sortWHEREiSortID=1003; GO
然后运行事务1,接着马上运行事务2,这种情况下某一个事务会提示发生了死锁,修改不成功。另外一个事务则完成。
第一点:使用TRY.CATCH让产生异常的事务能继续完成后面的代码。
第二点:使用WAITFORDELAY产生造成死锁的发生环境。
第三点:使用ERROR_NUMBER()来判断是否发生事务。
第四点:发生死锁,写SQLServer日志或者返回应用程序去写日志。便于检查日志的时候发现存在死锁并做相应的修改。
以上内容给大家介绍了SQL死锁检测的方法,希望大家喜欢。