MySQL隔离级别
MySQL的四种隔离级别
隔离级别比较:可串行化>可重复读>读已提交>读未提交
隔离级别对性能的影响比较:可串行化>可重复读>读已提交>读未提交
隔离级别越高,所需要消耗的MySQL性能越大(如事务并发严重性),为了平衡二者,一般建议设置的隔离级别为可重复读,MySQL默认的隔离级别也是可重复读。
Read Uncommitted(读未提交)
当前隔离级别是安全性最低的一级,默认不使用,或者说很少用于实际应用。
即所有事务都可以看到其他未提交事务的执行结果。当前隔离级别无法使用MVCC。
从字面意思即可理解,能够读取到其他事务尚未提交的内容。
图解:
Read Committed(读已提交)
它满足了隔离的简单定义:一个事务只能看见已经提交事务所做的改变。这种隔离级别 也支持所谓的不可重复读(Nonrepeatable Read),因为同一事务的其他实例在该实例处理其间可能会有新的commit,所以同一select可能返回不同结果。
图解:
Repeatable Read(可重读)(默认的隔离级别)
在可重复读隔离级别下,事务A只能在事务B修改过数据并提交后,自己也提交事务后,才能读取到事务B修改的数据。
可重复读隔离级别解决了脏读和不可重复读的问题,但可能发生幻读问题。
图解:
Serializable(可串行化)
这是最高的隔离级别,它通过强制事务排序,使之不可能相互冲突,从而解决幻读问题。简言之,它是在每个读的数据行上加上共享锁。在这个级别,可能导致大量的超时现象和锁竞争。
读读操作(不会阻塞)
读写操作(阻塞)
写读操作(阻塞)
写写操作(阻塞)
出现的问题
脏读
定义:脏读简单来说就是读到了一些脏数据,即不存在或者非法的数据
脏读只存在于 读未提交 这个隔离级别
默认原id = 1 , name = 张三
线程A | 线程B |
begin | |
begin | |
update * set name = 李四 where id = 1 | |
select name from * where id = 1(李四) | |
commit | |
rollback |
不可重复读
一个事务只能读到另一个已经提交的事务修改过的数据,并且其他事务每对该数据进行一次修改并提交后,该事务都能查询得到最新值。(不可重复读在读未提交和读已提交隔离级别都可能会出现)
默认原id = 1 , name = 张三
线程A | 线程B |
begin | |
select name from * where id = 1(张三) | |
update * set name = 李四 where id = 1 且 commit | |
select name from * where id = 1(李四) | |
update * set name = 王五 where id = 1 且 commit | |
select name from * where id = 1(王五) |
幻读
一个事务先根据某些条件查询出一些记录,之后另一个事务又向表中插入了符合这些条件的记录,原先的事务再次按照该条件查询时,能把另一个事务插入的记录也读出来。(幻读在读未提交、读已提交、可重复读隔离级别都可能会出现)
默认原id = 1 , name = 张三
线程A | 线程B |
begin | |
select name from * where id > 0(张三) | |
insert into user(id,name) values(2,李四) | |
select name from * where id > 0(张三,李四) |
就是线程A在查询同样的语句时候,读取到了其他线程插入的数据
四种隔离级别的比较
脏读 | 不可重复读 | 幻读 | |
读未提交 | 会 | 会 | 会 |
读已提交 | 不会 | 会 | 会 |
可重复读 | 不会 | 不会 | 会 |
串行化 | 不会 | 不会 | 不会 |