A deadlock is a situation where different transactions are unable to proceed because each holds a lock that the other needs. Because both transactions are waiting for a resource to become available, neither ever release the locks it holds.
死锁是这样产生的:不同的事务都持有对方所需要的锁,并同时等待对方释放锁。
一个select ··· lock in share mode与delete的死锁实例创建一个表,并插入数据:
mysql> CREATE TABLE t (i INT) ENGINE = InnoDB; Query OK, 0 rows affected (1.07 sec) mysql> INSERT INTO t (i) VALUES(1); Query OK, 1 row affected (0.09 sec)
| 事务A | 事务B | 结果 |
| select * from t where i = 1 lock in share mode; | 获取到S锁 | |
| delete from t where i = 1; | 试图获取X锁, 因事务A持有该行的读锁,因此进入锁等待队列。 | |
| delete from t where i = 1; | 死锁产生,此处事务A试图获取一个写锁,但是事务B在等待队列的前面,事务A无法将读锁升级为写锁。A等待B释放写锁,B等待A释放读锁。 |
InnoDB使用自动行级锁定。即使在只insert或delete一行的事务中,也可能出现死锁。这是因为这些操作不是真正的“原子”;它们会自动对插入或删除的行的(可能有多个)索引记录设置锁。
如何避免死锁
1. 事务比LOCK TABLE会好一些
2. 事务尽可能小,避免读写大量数据
3. 不同事务尽可能按照相同的顺序获取锁(select for update)
4. 在select for update 和 update where 上创建索引
5. 死锁出现的可能性与事务的隔离级别没有关系,死锁与写操作有关,隔离级别解决的是读取的可见性
6. SHOW ENGINE INNODB STATUS 可以查看死锁的原因。
7. 频繁出现死锁时,使能innodb_print_all_deadlocks
8. 使用select for update , select lock in share mode,建议隔离级别为RC
9. 操作多张表,或者同一张表的不同行时,建议使用相同的顺序,可以避免死锁的产生
10. 设置合适的索引,避免扫描大量的数据行
11. 尽可能使用一般select而不是for update,避免锁定
12. 串行化是最终方案



