死锁时产生多个事务的把握和要求对同一资源的锁并产生循环依赖。死锁发生在交易尝试锁定资源以不同的
顺序。两交易对股票价格表为例:
交易1
开始交易;
股价紧贴= 45.50,更新stock_id = 4日= '2002-05-01;
股价紧贴= 19.80,更新stock_id = 3日= '2002-05-02;
承诺;
交易# 2
开始交易;
更新股票价格高= 20.12 = 3 = '2002-05-02 stock_id
日期;
更新股票价格设定;
承诺;
如果不幸的话,每个事务都可以
执行第一个语句并将资源锁定在
进程中。每个事务在试图被锁定时执行第二行语句。除非有其他
原因来中断死锁,否则两个事务将一直
等待另一个语句完成。
为了
解决这个问题,数据库实现各种死锁
检测和超时机制。一个复杂的存储引擎,如InnoDB会
提示循环依赖并返回一个
错误立即。否则,僵局会导致
查询很慢。其他一些不好的做法是等待时间放弃。目前InnoDB
处理死锁的方式是回滚事务持有最少的行级锁。(几乎为回滚最简单的
参考)
锁的行为是由存储引擎决定的,因此,一些存储引擎可能在特定的
操作顺序中处于死锁状态,而另一些则可能不存在。死锁有两种:一些是不可避免的,因为实际的数据冲突,有些是由于存储引擎
工作方式造成的。
只有一个事务的部分或全部回滚才能打破死锁。死锁是事务
系统中的一个客观事实,在设计中您必须考虑处理死锁。一些业务系统可以从头开始重试事务。
如何处理死锁
死锁是事务数据库的典型问题,但除非
经常发生,否则您甚至不能
运行事务。他们一般都没有危险。通常
情况下,你必须写让他们随时准备补发交易如果你回滚事务因为死锁的
应用程序。
InnoDB使用自动行级锁。即使在只有插入或
删除一行交易的情况下,你可能会遇到一个僵局。这是因为这些操作是不是最小的,他们
设置自动锁上(可能是几个),插入或删除的行的索引记录。
您可以使用以下技术来处理死锁,以减少它们发生的可能性:
使用SHOW INNODB STATUS来确定最后的僵局的原因。这有助于你
调整应用程序以避免死锁。
随时准备补发交易如果失败因为死锁,死锁是不危险的,再试一次。
经常提交你的业务,小事情往往少一些冲突。
如果您正在使用锁读,请选择…更新或…锁定共享
模式),尝试使用较低的隔离级别,如读提交。
以固定的顺序访问表和行。事务形成一个定义良好的查询,并且没有死锁。
在您的表中添加一个精心挑选的索引。您的查询需要扫描较少的索引记录,从而设置更少的锁。
使用更少的锁定。如果您可以接受一个选择允许从旧快照返回数据,则不添加更新或锁定共享模式子句。最好在这里使用读提交隔离级别,因为同一事务中的每一个
连续读取
都是从它自己的新快照中读取的。
如果没有其他的事是有帮助的,使用表级锁序列化你的交易。使用锁表的事务表的
正确方式(如InnoDB)是设置自动提交= 0和叫不解锁表直到你明确提交事务。例如,如果你需要写表T1阅读从表中,你可以按如下做:
设置自动提交= 0;
锁定表t1写入,T2读取,…;
{在这里做表T1和T2的事情};
承诺;
打开表;
表级锁定使事务排队良好,避免死锁。
领导一个序列化的交易方式是
创建一个辅助
信号量表,其中只包含一个单一的线。让每个事务在访问其他表更新线。这样,所有的交易都发生在一个序列。注意,InnoDB即时死锁检测算法也可以租住在这种情况下,因为序列化的锁定是行级锁,超时的
方法,锁定MySQL表水平,必须解决死锁。
在应用程序中使用锁表的
命令,如果autocommit = 1,MySQL不设置innodb表锁。