1. 两阶段锁

下面的操作序列中,如果为两行数据加了行锁事务 B 的 update 语句执行时会是什么现象呢?假设字段 id 是表 t 的主键。**
**


在 InnoDB 中,行锁是在需要的时候加上,在**事务结束时释放。(最有可能造成锁冲突的行的读锁尽量往后放**

示例:

顾客 A 在影院 B 买电影票

操作如下

  1. 从顾客 A 账户余额中扣除电影票价;
  2. 给影院 B 的账户余额增加这张电影票价;
  3. 记录一条交易日志。

其中多个顾客买票可能造成 B 的账户行数据冲突。因此将 B 的操作放在最后。最大程度减少了事务之间的锁等待。

2. 死锁和死锁检测

示例:当行锁同时锁住 id=1 和 2 的两行数据

在这种情况下事务 A 等待 id=2 的行锁,事务 B 等待 id=1 的行锁。事务 A 和事务 B 互相都在等待对方无法释放的资源,从而进入了死锁。

解决方法

  • 设置获取锁等待时间:设置获取锁超时时间,如果超时则锁住的线程自动退出。通过 innodb_lock_wait_timeout 来设置等待时间默认为 50s
  • 发起死锁检测:发现死锁后主动回滚争抢锁的某一个事务。让其他事务继续执行。通过 innodb_deadlock_detect 设置为 on 表示开启逻辑。

死锁检测的缺点:

  1. 确保业务不会出现死锁,关闭死锁检测
  2. 控制并发度

3. 小结

  1. 读锁的两阶段协议:需要的时候加上、事务结束的时候释放。尽可能将影响并发度最大的锁往后放。减少其他锁的等待时间
  2. 死锁的形成,事务之间争抢不释放的锁资源。导致一直处于等待状态
  3. 死锁的解决方法:1. 设置锁等待时间 2. 开启死锁检测

  • 第一种,直接执行 delete from T limit 10000;
  • 第二种,在一个连接中循环执行 20 次 delete from T limit 500;
  • 第三种,在 20 个连接中同时执行 delete from T limit 500。

你会选择哪一种方法呢?为什么呢?

第二种,第三种容易造成死锁。第一种锁的范围太大导致获取锁的时间长。