详解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死锁检测的方法,希望大家喜欢。