本节以死锁的概念信息为基础第15.7.5.2节,“死锁检测”.它解释了如何组织数据库操作以最小化死锁以及应用程序中所需的后续错误处理。
死锁是事务性数据库中的一个经典问题,但它们并不危险,除非它们非常频繁,以至于您根本无法运行某些事务。通常,您必须编写应用程序,以便在事务因死锁而回滚时始终准备好重新发出事务。
InnoDB
使用自动行级锁定。即使在仅插入或删除单行的事务中,也可能出现死锁。这是因为这些操作并不是真的”原子”;它们自动对插入或删除的行的索引记录(可能有几个)设置锁。
您可以使用以下技术来处理死锁并降低死锁发生的可能性:
在任何时候,发行
显示引擎innodb状态
以确定最近死锁的原因。这可以帮助您优化应用程序以避免死锁。如果频繁的死锁警告引起关注,则通过启用
innodb_print_all_deadlocks
变量。关于每个死锁的信息(不仅仅是最新的死锁)都记录在MySQL中错误日志.在完成调试时禁用此选项。如果事务因死锁而失败,请随时准备重新发出事务。死锁并不危险。再试一次。
保持事务的规模和持续时间短,以使它们不容易发生冲突。
在进行一组相关更改后立即提交事务,以减少事务发生冲突的可能性。尤其不要留下互动mysql会话长时间打开,有一个未提交的事务。
当在一个事务中修改多个表,或者在同一个表中修改不同的行集时,每次都要按照一致的顺序执行这些操作。然后事务形成定义良好的队列,不会死锁。例如,将数据库操作组织为应用程序中的函数,或调用存储的例程,而不是编码多个类似的序列
插入
,更新
,删除
不同地方的表述。向表中添加精心选择的索引,以便查询扫描更少的索引记录并设置更少的锁。使用
解释选择
以确定MySQL服务器认为哪些索引最适合您的查询。使用更少的锁定。如果你能负担得起
选择
如果要从旧快照返回数据,则不需要添加更新
或为分享
条款。使用读过承诺
这里的隔离级别很好,因为同一事务中的每个一致读取都从自己的新快照中读取。如果没有其他帮助,可以使用表级锁序列化事务。正确的使用方法
锁表
使用事务表,例如InnoDB
表,是开始交易用的设置自动提交= 0
(不开始事务
)然后是锁表
,不要打电话打开表
直到您显式地提交事务。例如,如果需要向表写入数据t1
从表中读取t2
,你可以这样做:设置自动提交= 0;锁表t1写,t2读,…...对表t1和t2做点什么…提交;打开表;
表级锁阻止了对表的并发更新,避免了死锁,代价是在繁忙的系统中降低响应能力。
序列化事务的另一种方法是创建一个辅助”信号量”只包含一行的表。让每个事务在访问其他表之前更新该行。通过这种方式,所有事务都以连续的方式发生。注意
InnoDB
即时死锁检测算法也适用于这种情况,因为序列化锁是一个行级锁。对于MySQL表级锁,必须使用timeout方法来解决死锁。