对于数据库的默认隔离级别,Oracle默认的隔离级别是 RC,而MySQL默认的隔离级别是 RR 。
【为什么MySQL默认使用RR隔离级别?】那么,你知道为什么Oracle选择RC作为默认级别,而MySQL要选择RR作为默认的隔离级别吗?
Oracle的隔离级别Oracle支持ANSI/ISO SQL定义的Serializable和Read Committed两种隔离级别,根据Oracle官方文档的介绍,Oracle的隔离级别包括Read Committed、Serializable和Read-Only 。
文章插图
图片
Read-Only的隔离级别类似于Serializable,然而仅允许只读事务进行数据检索,不允许在事务中修改数据 , 除非使用者是SYS用户 。
在Oracle的这三种隔离级别中,显而易见,Serializable和Read-Only都不适合作为默认隔离级别,因此唯一的选择就是Read Committed了 。
MySQL的隔离级别与Oracle相比,MySQL提供的默认隔离级别范围更加广泛 。
首先,我们排除了Serializable和Read Uncommitted这两种级别,原因是一个隔离级别过高会影响并发度,另一个过低则存在脏读问题 。
剩下的RR和RC两种 , 如何选择呢?
MySQL在设计之初就旨在提供一个稳定的关系型数据库 。为解决MySQL单点故障问题,MySQL采取了主从复制机制 。
所谓的主从复制,即通过建立MySQL集群 , 以整体向外提供服务 。集群内的机器分为主服务器(Master)和从服务器(Slave),主服务器负责提供写服务,而从服务器则提供读服务 。
在MySQL主从复制过程中 , 数据的同步通过binlog进行 。简单来说,主服务器将数据变更记录到binlog中,然后将binlog同步传输给从服务器 。从服务器接收到binlog后,将其中的数据恢复到自己的数据库存储中 。
那么,binlog里记录的究竟是什么内容?它的格式又是怎样的呢?
MySQL的binlog主要支持三种格式,即statement、row和mixed 。MySQL从5.1.5版本开始支持row格式,在5.1.8版本中开始支持mixed格式 。
statement和row之间最重要的区别在于 , 当binlog的格式为statement时,binlog记录的是SQL语句的原文 。
由于MySQL早期仅支持statement这一种binlog格式,因此在使用提交读(Read Committed)和未提交读(Read Uncommitted)这两种隔离级别时都可能会出现问题 。
举个例子,有一个数据库表t1,表中有如下两条记录:
CREATE TABLE `t1` (`a` int(11) DEFAULT NULL,`b` int(11) DEFAULT NULL,KEY `b` (`b`)) ENGINE=InnoDB DEFAULT CHARSET=latin1;insert into t1 values(10,1);
接着开始执行两个事务的写操作:Session 2
set session transaction isolation level read committed;
set autocommit = 0;
set session transaction isolation level read committed;
begin;
begin;
delete from t1 where b < 100;
insert into t1 values(10,99);
commit;
commit;
以上两个事务执行之后,数据库里面的记录会只有一条记录(10,99),这个发生在主库的数据变更大家都能理解 。
即使 Session 1 的删除操作在 Session 2 的插入操作之后提交,由于 READ COMMITTED 的隔离级别,Session 2 的插入操作不会看到 Session 1 的删除操作,所以最后数据库中仍然会留下 Session 2 插入的记录 (10,99) 。以上两个事务执行之后,会在bin log中记录两条记录,因为事务2先提交 , 所以insert into t1 values(10,99);会被优先记录,然后再记录delete from t1 where b < 100;(再次提醒:statement格式的bin log记录的是SQL语句的原文)
这种行为是 READ COMMITTED 隔禽级别的一种特性,它会在事务开始时创建一个快照 。确保事务之间的隔离性 , 避免了数据不一致性的问题 。
这样bin log同步到备库之后,SQL语句回放时 , 会先执行insert into t1 values(10,99);,再执行delete from t1 where b < 100; 。
这时候,数据库中的数据就会变成 EMPTY SET , 即没有任何数据 。这就导致主库和备库的数据不一致了?。。?
为了解决这种问题,MySQL将数据库的默认隔离级别设置为Repeatable Read 。在Repeatable Read隔离级别下,针对更新数据时会不仅对更新的行加行级锁 , 还会增加GAP锁和next-key锁 。在上述例子中,当事务 2 执行时,由于事务 1 添加了GAP锁和next-key锁 , 这将导致事务 2 执行被阻塞,需要等待事务 1 提交或回滚后才能继续执行 。
推荐阅读
- 电动车电池正常寿命是多久?为什么有的电池用一年就报废?有三大原因!
- 为什么老司机经常用S挡开车,一直用S挡会伤车吗?新手:早点知道就好了
- 为什么高档车都用宽轮胎,普通车都用窄轮胎?
- 为什么开车时有人喜欢把胳膊搭在车窗上?内行人告诉你,这是个高手
- 牛脸肉为什么不能多吃 牛脸肉怎么不能多吃
- 吴秀波为什么要与小三同归于尽?
- 蜈蚣怎么会出现在房间 蜈蚣为什么会出现在屋里
- 全麦粉可以做油茶面吗 全麦粉有油茶面味道吗为什么
- 石油的计算单位为什么是桶不是吨?一桶石油有多重?今天才明白
- 取保候审后又采集个人信息是为什么呢 取保候审为什么会人格测试呢