前奏
MySQL 的默认事务隔离级别为 Repeatable Read。而 ORACLE、SQLServer 等的默认隔离级别使用的是 Read Committed 模式,为什么呢?
开始我们的内容,相信大家一定遇到过下面的一个面试场景
面试官:“讲讲 mysql 有几个事务隔离级别?”
你:“读未提交,读已提交,可重复读,串行化四个!默认是可重复读”
面试官:“为什么 mysql 选可重复读作为默认的隔离级别?”
(你面露苦色,不知如何回答!)
面试官:“你们项目中选了哪个隔离级别?为什么?”
你:“当然是默认的可重复读,至于原因…呃…”
(然后你就可以回去等通知了!)
为了避免上述尴尬的场景,请继续往下阅读!
Mysql 默认的事务隔离级别是可重复读 (Repeatable Read),那互联网项目中 Mysql 也是用默认隔离级别,不做修改么?
OK,不是的,我们在项目中一般用读已提交 (Read Commited) 这个隔离级别!
what!居然是读已提交,网上不是说这个隔离级别存在不可重复读和幻读问题么?不用管么?好,带着我们的疑问开始本文!
我们先来思考一个问题,在 Oracle,SqlServer 中都是选择读已提交 (Read Commited) 作为默认的隔离级别,为什么 Mysql 不选择读已提交 (Read Commited) 作为默认隔离级别,而选择可重复读 (Repeatable Read) 作为默认的隔离级别呢?
Why?Why?Why?
这个是有历史原因的,当然要从我们的主从复制开始讲起了!
主从复制,是基于什么复制的?
是基于 binlog 复制的!这里不想去搬 binlog 的概念了,就简单理解为 binlog 是一个记录数据库更改的文件吧~
binlog 有几种格式?
OK,三种,分别是:
statement: 记录的是修改 SQL 语句
- row:记录的是每行实际数据的变更
mixed:statement 和 row 模式的混合
那 Mysql 在 5.0 这个版本以前,binlog 只支持 STATEMENT 这种格式!而这种格式在读已提交 (Read Commited) 这个隔离级别下主从复制是有 bug 的,因此 Mysql 将可重复读 (Repeatable Read) 作为默认的隔离级别!
接下来,就要说说当 binlog 为 STATEMENT 格式,且隔离级别为读已提交 (Read Commited) 时,有什么 bug 呢?如下图所示,在主 (master) 上执行如下事务