mysql的行索是在引擎实现的。但并不是所有引擎都支持行锁。不支持行锁的引擎只能使用表锁。
- 不支持行锁意味着并发控制只能使用表锁,对于这种引擎的表,同一张表上任何时刻只能有一个更新在执行,这就会影响到业务并发度
从两阶段锁说起
-
事务 B 的 update 语句会被阻塞,直到事务 A 执行 commit 之后,事务 B 才能继续执行。
-
事务 A 持有的两个记录的行锁,都是在 commit 的时候才释放的。
-
在 InnoDB 事务中,行锁是在需要的时候才加上的,但并不是不需要了就立刻释放,而是要等到事务结束时才释放。这个就是两阶段锁协议。
- 如果你的事务中需要锁多个行,要把最可能造成锁冲突、最可能影响并发度的锁尽量往后放。
死锁和死锁检测
- 定义
当并发系统中不同线程出现循环资源依赖,涉及的线程都在等待别的线程释放资源时,就会导致这几个线程都进入无限等待
的状态,称为死锁
- 出现死锁的策略
1、直接进入等待,直到超时。这个超时时间可以通过参数 innodb_lock_wait_timeout 来设置。
(InnoDB默认是50s,正常在线服务接受不了。设置太小容易误伤)
2、发起死锁检测,发现死锁后,主动回滚死锁链条中的某一个事务,让其他事务得以继续执行。将参数 innodb_deadlock_detect 设置为 on,表示开启这个逻辑。
(默认值是on,开启的,当然对数据库有额外负担)
- 死锁检测的过程
每当一个事务被锁的时候,就要看看它所依赖的线程有没有被别人锁住,如此循环,最后判断是否出现了循环等待,
也就是死锁
- 死锁检测的消耗
死锁检测的耗费代价是 O(n2)级别的。假设有 1000 个并发线程要同时更新同一行,那么死锁检测操作就是 100 万这个量级的。
-
解决死锁的思路
- 确保业务不会出现死锁,可以临时关掉死锁检测
- 控制并发度