为什么建议MySQL隔离级别为RC

524 阅读3分钟

前言

用过MySQL数据库的都知道,它有四种隔离级别:

  1. 读未提交(Read Uncommitted),指一个事务还没提交时,它做的变更就能被其他事务看到;
  2. 读提交(Read Committed),指一个事务提交之后,它做的变更才能被其他事务看到;
  3. 可重复读(Rpeatable Read),指一个事务执行过程中看到的数据,一直跟这个事务启动时看到的数据是一致的,MySQL InnoDB 引擎的默认隔离级别;
  4. 串行化(Serializable);会对记录加上读写锁,在多个事务对这条记录进行读写操作时,如果发生了读写冲突的时候,后访问的事务必须等前一个事务执行完成,才能继续执行。

并且我们知道MySQL默认的隔离级别为可重复读RR,但当我们使用阿里云数据库时,它会建议我们使用RC的隔离级别,并且各大互联网大厂的生产环境数据库也基本都会将隔离级别调整为RC,这么做的原因是什么呢?

为什么MySQL默认隔离级别为RR

要说明这个问题,我们得从MySQL历史发展历程开始说起。大家都知道,MySQL支持主从同步、读写分离,数据之所以能从主节点同步到从节点,靠的就是binlog日志,现在我们都知道,这个日志有三种格式,statement、row和mixed(混合模式),早期只有一种statement格式,这种格式记录的是原生sql语句,在RC隔离级别下(行级锁只存在记录锁,没有间隙锁和组合锁),从节点拿到这种格式的binlog日志进行回放时,当使用窗口函数或者某些并发修改场景下,会造成数据错乱。当时MySQL为了避免这种问题,将MySQL默认隔离级别设置为RR,一直延用至今。

隔离级别RR和RC的区别

快照读

MySQL里面有两种读,当前读和快照读,对于RR和RC这两种隔离级别,快照读是不同的。

  • 在 RR 中,快照会在事务中第一次SELECT语句执行时生成,后续除非当前事务对数据进行了更新操作,否则快照读读取的数据都会和第一次的一样。
  • 在 RC 中,每次读取都会重新生成一个快照,总是读取行的最新版本。

行级锁

在MySQL 中,行级锁有三种,分别是(记录锁)Record Lock、(间隙锁)Gap Lock和(记录锁和间隙锁的组合锁)Next-Key Lock。

  • 在 RR 中,还增加了(间隙锁)Gap Lock和(记录锁和间隙锁的组合锁)Next-Key Lock这两种锁。
  • 在 RC 中,只存在(记录锁)Record Lock,对一行记录的索引加锁;

主从同步

在 RR 中,主从同步使用到的binlog可以使用statement、row和mixed(混合模式)三种的任一种; 在 RC 中,binlog日志只能选择row或者mixed(混合模式)。

MySQL隔离级别改为RC有啥好处

  • RC少了两种行级锁,大大提高了并发,并且降低死锁发生的概率;
  • RR可重复读,在一个事务里,其他事物更新数据且提交事物后,当前事务会延用之前的快照版本,导致读取不到最新且正确的数据,这其实在很多业务场景下并不合理。