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.
死锁是这样产生的:不同的事务都持有对方所需要的锁,并同时等待对方释放锁。

创建一个表,并插入数据:
- 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. 串行化是最终方案