MySQL 的默认事务隔离级别是 Repeatable Read(可重复读)。
Oracle 的默认事务隔离级别是 Read Committed(读已提交)。
这是一个比较“怪”的现象。毕竟这两个事务隔离级别是差异是比较大的,而这两个数据库都是通用型的产品。
真实原因是MySQL为了规避一个数据复制场景中的缺陷,而选择 Repeatable Read 作为默认隔离级别。
基于 Statement 的 binlog
binary log 的主要用途
MySQL的 binary log 记录了数据库的“事件”。这些“事件”描述了数据库的改动,包括 表的创建、数据修改等。
binary log 主要用于:
binary log 的三种模式
binary log 有三种模式:
-
Statement:记录的是可能改变数据的SQL语句
-
Row:记录的是每行数据的变更
-
混合模式:
默认使用 Statement 格式的记录;
当遇到可能引起 “基于Statement的数据复制问题” 时自动转换为 Row 模式。
基于Statement的数据复制问题
上述两个事务的隔离级别都是 Read-Committed。
真实的执行顺序是 先删后插。而 binlog 中记录的 Statement 顺序为 先插后删。
当基于这份 Statement 格式的 binlog 进行主从复制或恢复数据时,得到的最终数据与实际情况不符。
两种解决方法:
-
选用 Row 模式 的 binlog
针对实际数据行的记录当然可以准确反映改动历史
-
选用 Repeatable-Read 事务隔离级别
“可重复读”隔离级别下,delete、insert 等语句会对数据加 间隙锁。上述Session2中的insert语句将被阻塞,直到session1 commit;
因为早期MySQL只支持 Statement 格式的 binlog,所以只能采用 Repeatable-Read 隔离级别来规避数据不一致的风险。
从 5.7.7 开始,MySQL的默认 binlog 格式已经是 ROW
选哪种事务隔离级别?
大多数项目中可以选 Read-Committed(读已提交),既降低死锁几率,又能提升并发性能。同时选用 Row 模式的binlog。
当然,这类 “最终一致性”的事务解决方案可能无法满足某些特殊项目的需求,需要采用 Serializable (串行)的隔离级别。