实例分析数据库死锁的产生与发展,实例分析数据库死锁的产生与处理
最近在系统运行过程中,会提示“该事务(进程ID 54)被另一个进程锁定,已被选为死锁牺牲品。请重新运行交易。
以前也发生过,但我不知道从何说起。朱总经理建议,所有与该表相关的sql语句都要围绕错误语句访问的表进行查找,看是否会造成死锁。其实听到这个提示的时候,脑子也是一片混乱。后来看到牺牲的sql语句有三个表,而且是最常用的三个表。按照朱的想法工作量有多大?另外,我对数据库死锁的一些细节还有点不清楚。这不是大海捞针吗?
第二天,我想了一个办法,先重现这个死锁,然后通过数据库找到死锁前后的sql,这样范围就小了很多(我不敢肯定我还能了解死锁的细节,当然这是事先没有预料到的)。
照你说的做就行了,第一步就是重现僵局。就在很久以前,写了一个机器人来测试这个系统的并发性,可以模仿多个客户端做常规操作。但是有些天没更新了,修改了2个小时左右。最后运行,还不错,可以用。18机器人做常规操作,我在客户端做非常规操作。客户端一停止,我就运行exec sp_who_lock。
手工排序后,如下图:
54被86阻止更新Sale _ Object Set objstateid=@ objstateid
1,76,86,101被54 select * from sale _ objstate,sale _ object,sale _ subsvc阻止
60、66被71更新Sale _ Object Set objstateid=@ objstateid阻止
理解“独占锁X”和“共享锁S”的含义可以总结如下:“”
- select在ReadCommitted事务中添加共享锁,在RepeatableRead事务中添加排他锁;
-在插入、更新和删除期间始终应用排他锁;
- update必须等待select事务释放共享锁并将其转换为独占锁,然后才能执行;
-如果事务T将S锁添加到数据对象A,其他事务只能将S锁添加到A,而不能添加X锁,直到T释放A上的S锁。
并在调用上面的相关sql语句之前查询代码中的语句,结论如下:
-86号流程已重新提交
86插入SALE_ObjState以获得SALE_ObjState的独占锁
86 select SALE_ObjState持有独占锁
8更新需要SALE_Object的独占锁。
-54号过程可重复读取
54 select * from SALE_SubSvc,SALE_Object,SALE_ObjState
依次获取sale _ subsvc和sale _ object的独占锁,但是需要SALE_ObjState的独占锁,但是被86占用,无法获取(这里是我自己根据sql中的from语句依次获取表的锁,因为作为一个程序,不可能同时锁定三个表,必须逐个添加,所以……)
过程71的过程与过程86的过程相同(此处省略)
因为进程54使用了更高级别的事务,这也是死锁的关键点。
解决方案:
1.如果程序中54个进程的查询不需要使用RepeatableRead transaction,那么将其修改为ReadCommitted transaction。
2.如果程序中必须使用RepeatableRead事务,必须通过改变sql语句SELECT * FROM SALE _ SUSBVC,SALE_Object和SALE_ObjState中SALE _ object和SALE _ objstate的顺序来实现。但这种交换也是有风险的,因为你不知道是否还有其他地方会出现死锁。这个解比较复杂,理论上很难详细讨论。
本文的目的是让读者了解数据库死锁的一些细节。如果有不清楚的描述,请指出来,我一定会回答。
由于我的水平是菜鸟水平,如果理解不正确请指正!
郑重声明:本文由网友发布,不代表盛行IT的观点,版权归原作者所有,仅为传播更多信息之目的,如有侵权请联系,我们将第一时间修改或删除,多谢。