MySQL事务隔离级别
简单来说,事务就是要保证一组数据库操作,要不全部成功,要不全部失败,在 MySQL 中,事务支持是在存储引擎层面的,比如 MySQL 的原生 MyISAM 存储引擎就不支持事务,这也是 MyISAM 被 InnoDB 取代的重要原因。
一、隔离性
事务的隔离性,就是我们常说的 ICAD(Atomicity,Consistency,Isolation,Durability,即原子性
,一致性
,隔离性
,持久性
)
- 原子性:事务的最小单位,保证 MySQL 的一组数据库操作,要不全部成功要不全部失败
- 一致性:执行事物前后,数据资源保持一致,比如转账,无论转账是否成功,转账者和收款者的总额应该是不变的。
- 隔离性:并发访问数据库时,不同事物之间的数据应该是隔离的
- 持久性:一个事物被提交后,他对数据库的数据的改变是持久的,即使数据库发生故障数据也不会变化
当数据库上有多个事务同时执行的时候,就可以出现脏读
,不可重复读
,幻读
的问题
- 脏读:A 事务中,读取到 B 事务中修改但未提交的数据,之后 B 事务回滚,导致 A 事务读取到的是一个不存在的数据,即脏数据
- 不可重复读:A 事务中读取字段 name=lisi,此时 B 事务修改 name=zhangsan 并提交,之后 A 在事务中再次读取 name=zhangsan,这就导致 A 在同一个事务中两次读取到的数据不一致
- 幻读:幻读跟不可重复读有点像,不过不可重复读针对的同一条记录不可重复读取,幻读指的是 A 事务读取 name=lisi 有四条记录,此时 B 事务删除了一条 name=lisi 的记录,之后 A 再次去读 name=lisi 只能读取到三条记录了,幻读针对的是记录的数量,可以看作是不可重复读的特例
为了解决以上问题,就有了隔离级别的概念
二、隔离级别
再说隔离级别之前,我们应该知道,隔离的越严格,效率就最低
,因此我们很多时候,需要在隔离级别和效率之间寻找一个平衡点
SQL 标准的事务隔离级别包括:读未提交(read uncommitted)
,读已提交(read committed)
,可重复读(repeatable read)
,串行化(serializable)
- 读未提交:一个事务还没提交时,它做的变更就能够被其他事务看到
- 读已提交:一个事务提交后,它做的变更才能被其他事务看到
- 可重复读:一个事务执行过程中看到的数据,总跟这个事务在启动时看到的数据是一致的,当然在可重复读隔离级别下,未提交变更对其他事务也是不可见的
- 串行化;对于同一行记录,写会加写锁,读会加读锁,当出现读写锁冲突的时候,后访问的事务必须等前一个事务执行完成,才能继续执行
三、案例
mysql> create table T(c int) engine=InnoDB;
insert into T(c) values(1);
我们来看看在不同的隔离级别下,事务 A 查到的 V1,V2,V3 分别是什么值
- 读未提交:A 事务能够读取到 B 事务更改未提交的数据,所以 V1=2,V2=2,V3=2
- 读已提交:A 事务只能读取到 B 事务提交后的数据,所以 V1=1,V2=2,V3=2
- 可重复读:在 A 事务开启后,读取到的数据都是一样的,所以 A 事务开始的时候值是 1,所以 V1=1,V2=1,V3=2
- 串行化:在事务 B 将 1 改成 2 的时候,会被锁住,直到 A 事务提交后,事务 B 才能继续执行,所以从 A 的角度来看,V1=1,V2=1,V3=2
在实现上,数据库里面会创建一个视图,访问的时候以视图的逻辑结果为准
- 在
可重复读隔离级别下,这个事务是事务启动时创建的
,整个事务存在期间都用整个视图 - 在
读已提交隔离级别下,整个视图是在 SQL 语句开始执行的时候创建的
- 这里值得注意的是,
读未提交隔离级别下直接返回记录上的最新值
,没有视图概念 - 串行化隔离级别则是通过直接加锁的方式来避免并行访问
四、总结
在不同的隔离级别下,数据库行为是不同的,Oracle数据库默认隔离级别是读已提交
,MySQL默认隔离级别是可重复读
,如果存在 Oracle 迁移到 MySQL,为保证数据库隔离级别一致,需要将 MySQL 的隔离级别改成读已提交
MySQL 配置的方式是,将启动参数transaction-isolation
的值设置成READ-COMMITTED
,可以使用show variables like 'transaction_isolation';
来查看当前隔离级别
正常情况下,为了保证效率,我们一般都会把事务隔离级别调整成读已提交
,那么什么时候需要可重复读的场景呢
?大多数在做数据校对
的时候,不希望有其他事务来干扰数据,启动可重复读是很方便的
我是一零贰肆,一个关注Java技术和记录生活的博主。
欢迎扫码关注“一零贰肆”的公众号,一起学习,共同进步,多看路,少踩坑。