事务隔离级别 | 脏读 | 不可重复读 | 幻读 |
---|---|---|---|
读未提交(read-uncommitted) RU | 是 | 是 | 是 |
读提交(read-committed) RC | 否 | 是 | 是 |
可重复读(repeatable-read) RR | 否 | 否 | 是 |
串行化(serializable) | 否 | 否 | 否 |
可重复读是 MySQL 的默认级别
具体解释:
读未提交
MySQL 事务隔离其实是依靠锁来实现的,加锁自然会带来性能的损失。而读未提交隔离级别是不加锁的,所以它的性能是最好的,没有加锁、解锁带来的性能开销。但有利就有弊,这基本上就相当于裸奔啊,所以它连脏读的问题都没办法解决。
任何事务对数据的修改都会第一时间暴露给其他事务,即使事务还没有提交。
set global transaction isolation level read uncommitted;
读提交
既然读未提交没办法解决脏数据问题,那么就有了读提交。读提交就是一个事务只能读到其他事务已经提交过的数据,也就是其他事务调用 commit 命令之后的数据。那脏数据问题迎刃而解了。
读提交事务隔离级别是大多数流行数据库的默认事务隔离界别,比如 Oracle,但是不是 MySQL 的默认隔离界别。
set global transaction isolation level read committed;
可重复读
可重复是对比不可重复而言的,上面说不可重复读是指同一事务不同时刻读到的数据值可能不一致。而可重复读是指,事务不会读到其他事务对已有数据的修改,即使其他事务已提交,也就是说,事务开始时读到的已有数据是什么,在事务提交前的任意时刻,这些数据的值都是一样的。但是,对于其他事务新插入的数据是可以读到的,这也就引发了幻读问题。
set global transaction isolation level repeatable read;
要说明的是,当你在 MySQL 中测试幻读的时候,并不会出现幻读的结果,幻读并没有发生,MySQL 的可重复读隔离级别其实解决了幻读问题
实际上可重复读没有完全解决幻读问题。
总结一下就是,MVCC解决了幻读的问题吗?严谨来说并没有解决,MVCC利用版本链,可以在快照读模式下解决幻读问题,并且不用加锁解决读写冲突问题,极大的增加了数据库的并发量。另一方面,在当前读的模式下,仅仅依靠MVCC不能解决幻读问题,必须依赖next-key锁(行锁+间隙锁)来解决,这是因为当前读必须获取最新数据。而行锁是把符合条件的数据上锁,控制update,delete操作,间隙锁则是把符合条件的附近区间锁住,解决insert插入,即可解决幻读问题。
串行化
串行化是4种事务隔离级别中隔离效果最好的,解决了脏读、可重复读、幻读的问题,但是效果最差,它将事务的执行变为顺序执行,与其他三个隔离级别相比,它就相当于单线程,后一个事务的执行必须等待前一个事务结束。