Mysql 的事务隔离与实现
本文讨论只针对 mysql 的 innodb 存储引擎。因为只有 innodb 支持事务,所谓事务隔离必须支持事务才有讨论的意义。
1. 为什么需要需要隔离?
主要是为了解决以下三类问题:脏读、不可重复读、幻读
脏读:一个事务可以读取到其他事务未提交的数据
不可重复读:事务 A 在其执行过程中,针对一条数据的两次 select 获取到的值不一致。通常是因为其他事务在事务 A 执行过程中,更新了数据并提交导致
幻读:幻读是针对数据插入场景,指的是事务 A 在执行过程中,针对某条数据 a 已经更新为 b,但此时有其他事务再一次插入与 a 一摸一样的数据,事务 A 再次 select 会再次读到数据 a,感觉像是之前的更新未起效果,出现幻觉
2. 事务隔离级别?
事务隔离级别分为 4 个层次,性能依次递减,隔离强度递增:读未提交、读提交、可重复读、串行化。
mysql 默认隔离级别是可重复读,其他则默认是读已提交
mysql 在可重复读级别解决了幻读的问题(行锁+间隙锁)
3. 事务隔离的实现?
读未提交:可以理解为没有什么隔离效果,不需要特殊实现,未加锁
串行化:读时加共享锁,此时其他事务只能读不能写;写时加排他锁,此时其他事务不可读,不可写,事务的执行变成串行
读已提交 &可重复读:innodb 采用 mvcc 方式实现可重复读。即每条记录有一个版本链,版本链上每个 row 包含了一个 trx_id 字段,记录产出当前版本数据的事务 id。读已提交和可重复读的不同在于生成快照时机的不一致(读写操作是基于当前快照进行操作的)。所谓快照满足以下条件:
当前事务内更新,可以读到
版本未提交,不能读到
版本已提交,但是在快照创建后提交,不能读到
版本已提交,在快照创建之前提交,可以读到。
所以,可重复读在事务开始阶段创建快照,则事务执行过程中无论其他事务如何更新数据,读的是自己的快照;读已提交,在每次执行 sql 时都创建一次快照,因此只能保证不读到未提交数据,一旦已提交,则可以读到,不保证可重复读。
版权声明: 本文为 InfoQ 作者【Geek_快去搞学习】的原创文章。
原文链接:【http://xie.infoq.cn/article/afba7be7970aaf496b9bf3a19】。未经作者许可,禁止转载。
评论