15.7.5.3 怎样降低死锁概率
在事务性数据库中,死锁是一个经典问题,但是一般不是很危险,除非死锁频繁发生,以至于一些事务根本无法执行。通常,你再编写
应用程序时必须考虑到事务因死锁回滚后重新发布的问题。
InnoDB使用行级锁。即使你只插入或删除一条记录,也有可能发生死锁。原因是这些操作不是原子的:它们通常会锁定相关的索引记录(
可能是多个)。
可以使用下面的方法来降低死锁发生的概率:
- 使用SHOW ENGINE INNODB STATUS来查看最近发生的死锁。这可以帮助你进行程序调优,从而避免死锁。
- 如果死锁频繁发生。可以开启innodb_print_all_deadlocks变量来收集更多的调试信息,这些信息被记录在MySQL错误日志中。在你
结束调试后,请禁用这个选项。
- 如果发生了死锁,记得重试。死锁不可怕,重试一下。
- 保证事务小,耗时短,这可以降低锁冲突的概率。
- 在做了一系列相关的修改后,马上提交。记得,不要在一个交互式会话中,让一个事务长时间处于未提交状态。
- 如果你使用锁定读(SELECT ... FOR UPDATE 或 SELECT ... FOR SHARE),尝试使用一个低的隔离级别,比如READ COMMITTED。
- 在一个事务中修改不同的表,或是通一张表中的不同记录的集合,保证这些操作的顺序一致。事务的操作顺序处理好后,就不会发生死锁。
例如,在应用代码中,将数据库操作封装进函数中,或者调用存储过程,不要在不同的地方写一些相似的语句。
- 添加选择性好的索引,这样查询时可以扫描更少的记录,设置更少的锁。使用EXPLAIN SELECT来查看MySQL为你的查询选择的最合适的索引。
- 使用更少的锁。如果你可以接受一个旧版本的快照数据,就不要使用FOR UPDATE 或FOR SHARE。最好使用READ COMMITTED隔离级别,因为
在这个隔离级别下,同一个事务中,每一个一致性读都会创建一个快照。
- 如果所有的方法都不管用,那可以考虑锁定表。表级锁可以阻止并发更新,避免死锁,代价是降低了系统的响应能力。
- 另一个使事务串行化的方法是创建一个只有一列的二级索引。在执行事务钱,每次更新相关记录钱,先更新相关行。