在上一篇文章中,我跟你介绍了 MySQL 的全局锁和表级锁,今天我们就来讲讲 MySQL 的行锁。
MySQL 的行锁是在引擎层由各个引擎自己实现的。但并不是所有的引擎都支持行锁,比如 MyISAM 引擎就不支持行锁。不支持行锁意味着并发控制只能使用表锁,对于这种引擎的表,同一张表上任何时刻只能有一个更新在执行,这就会影响到业务并发度。InnoDB 是支持行锁的,这也是 MyISAM 被 InnoDB 替代的重要缘故原由之一。-
我们今天就主要来聊聊 InnoDB 的行锁,以及怎样通过减少锁冲突来提拔业务并发度。
行锁是什么
顾名思义,行锁就是针对数据表中行记录的锁。这很好理解,比如事务 A 更新了一行,而这时间事务 B 也要更新同一行,则必须等事务 A 的操作完成后才气举行更新。
固然,数据库中另有一些没那么一览无余的概念和计划,这些概念如果理解和使用不当,容易导致程序出现非预期行为,比如两阶段锁。
两阶段锁协议
我先给你举个例子。在下面的操作序列中,事务 B 的 update 语句执行时会是什么征象呢?假设字段 id 是表 t 的主键。
这个问题的结论取决于事务 A 在执行完两条 update 语句后,持有哪些锁,以及在什么时间释放。你可以验证一下:实际上事务 B 的 update 语句会被阻塞,直到事务 A 执行 commit 之后,事务 B 才气继承执行。
知道了这个答案,你一定知道了事务 A 持有的两个记录的行锁,都是在 commit 的时间才释放的。
也就是说,在 InnoDB 事务中,行锁是在需要的时间才加上的,但并不是不需要了就立刻释放,而是要等到事务结束时才释放。这个就是两阶段锁协议。
知道了这个设定,对我们使用事务有什么帮助呢?那就是,如果你的事务中需要锁多个行,要把最可能造成锁冲突、最可能影响并发度的锁尽量往后放。我给你举个例子。
示例:
假设你负责实现一个影戏票在线交易业务,顾客 A 要在影院 B 购买影戏票。我们简化一点,这个业务需要涉及到以下操作: