Mysql之四-行锁和MVCC版本控制

行锁

1.在 InnoDB 事务中,行锁是在需要的时候才加上的,但并不是不需要了就立刻释放,而是要等到事务结束时才释放。这个就是两阶段锁协议。
2.如果你的事务中需要锁多个行,要把最可能造成锁冲突、最可能影响并发度的锁尽量往后放.
(也就是说让你的那一行锁尽量慢加)
(先插入再更新, 更新会涉及到行锁的竞争, 所以先插入会减少锁等待)

死锁和死锁检测

当并发系统中不同线程出现循环资源依赖,涉及的线程都在等待别的线程释放资源时,就会导致这几个线程都进入无限等待的状态,称为死锁。
1.可以调整innodb_lock_wait_timeout, 直到超时就失败(默认50s)
2.发起死锁检测,发现后, 主动回滚, innodb_deadlock_detect设置为on;(默认on)

  • O(n2)复杂度
  • 可以用多表来记录避免热数据更新在同一行, 结合业务;

MVCC多版本控制

1.一个事务启动时会神奇一个事务ID, (严格递增)
2.每行数据有多个版本,每次更新,会产生一个数据版本,并且把事务id给这个版本, 记为row trx_id
3.一个事务启动有了事务id后, 依据于此, 来获取确定每行的数据版本;
4.获取当前启动未提交的事务,最低的id为低水位, 最大的加一为高水位;
5.一个数据的row trx_id, 如果

  • 低于低水位, 可见;
  • 高于高水位, 不可见;
  • 如果在中间, 且在上面获取的数组中, 不可见;反之可见;
    6.结合上面的, 如果是RR模式, 那每次寻找数据,都要从多版本数据里面把真正的数据找出来;

更新逻辑(当前读)

更新数据都是先读后写的,而这个读,只能读当前的值,称为“当前读”(current read)。
可重复读的核心就是一致性读(consistent read);而事务更新数据的时候,只能用当前读。如果当前的记录的行锁被其他事务占用的话,就需要进入锁等待。

幻读

MVCC并没有解决幻读的问题, 只不过是在RR的模式下, 普通的读并不会有幻读问题(快照读), 当前读才可能会导致幻读;
(幻读无法阻止新插入的记录, 这里会导致binlog记录恢复有误(顺序))

间隙锁(Gap Lock) 解决幻读(RR模式下才会生效的)

(语法: lock in the share mode)
间隙锁是一个比较特殊的东西
间隙锁不一样,跟间隙锁存在冲突关系的,是“往这个间隙中插入一个记录”这个操作

间隙锁和行锁合称 next-key lock,每个 next-key lock 是前开后闭区间

1
2
select … for update
若某一行不存在, 会把间隙的这些行都加了锁

间隙锁的引入,可能会导致同样的语句锁住更大的范围,这其实是影响了并发度的。

1
2
互联网公司为了更高的并发度, 一般设置成了RC模式, 然后把binlog设置为row模式即可,
这样没了间隙锁, 提高并发, 具体看业务
hyhcoder wechat
扫码关注我的个人订阅号