当前位置:Gxlcms > 数据库问题 > MySQL事务的隔离级别

MySQL事务的隔离级别

时间:2021-07-01 10:21:17 帮助过:2人阅读

:未提交的数据,也就是没有被持久化到磁盘的数据,被称之为脏数据,因此,在当前隔离级别下,会出现脏读的问题。也就是读取到了未提交的脏数据。


READ COMMITTED,读提交,指的是事务可以读取到其他事务已经提交的数据。

测试如下,恢复到初始数据。

session-A,开启离级别为 read committed的事务A

— session-A
— 设置隔离级别为 read committed
set transaction isolation level read committed;
start transaction;

session-B,开启另一个事务B,更新数据

— session-B
start transaction;
— 更新一条记录
update kang_tx set num=20 where num=2;
— 不执行commit提交

session-A,测试是否可以读取到其他事务未提交的数据

— session-A
— 等待session-B更新数据后执行
select * from kang_tx;

结果:

技术分享

session-B,提交事务B

— session-B
— 执行提交
commit;

session-A,测试是否可以读取到其他事务提交的数据

— session-A
— 等待session-B提交后执行
select * from kang_tx;

结果:

技术分享

解释:事务A,级别为read committed,以为这可以读取到其他事务提交的数据。当事务B更新数据后,直接在事务A中读取,没有读取到,因为此时没有提交,但当事务B执行提交后,事务A读取到了更新的数据,因为数据已经提交了,这就是读提交隔离级别!

该隔离级别会解决脏读问题,但是会出现不可重复读和幻读问题,先来看不可重复读问题:

不可重复读: 读到提交的数据,会带来一个问题,就是当事务A读取到某数据后,此时事务B提交了对该数据的修改,之后事务A再次读取该数据,数据就变成了事务B提交后数 据。也就意味着事务A内前后两次读取的同一数据是不相同的。这就是不可重复读。因为不能保证重复读的结果一致。也是当前隔离级别所带来的问题。


REPEATABLE READ,重复读,指的是同一事务内,可以反复的读取同一数据,不会被其他事务所修改。就是刚刚读提交时的问题。

测数如下,重新初始数据:

session-A,开启repeatable read级别的事务,先读取一次:

— session-A
— 设置隔离级别为 repeatable read
set transaction isolation level repeatable read;
start transaction;
— session-A
— 等待session-B提交后执行
select * from kang_tx;

结果:

技术分享

session-B,开启事务,并提交

— session-B
start transaction;
— 更新一条记录
update kang_tx set num=20 where num=2;
— 执行提交
commit;

session-A,测试读取到的数据是什么:

技术分享

解释:当前隔离级别下,如果事务A已经读取过了某些数据,此时事务B更新了这些数据。事务A再次读取该数据时,不会受事务B的影响,即使事务B已经提交了修改。这就是可重复读的隔离级别。

注意,如果事务A没有读取的数据,事务B提交了,事务A再后读取的话,是可以读取到提交的数据的。因为这不是重复读。

在标准的可重复读级别下,会出现幻读问题。

幻读: 假设初始数据有:1,2,4,5,8。事务A先读取的小于等于4(where num<=4)的数据1,2,4,此时事务B向表中插入数据3并提交,然后事务A再次读取小于等于4的数据,就会发现会读取到事务B插入的3数据。 这个现象就是幻读,这个3数据,对于事务A来说,就像幽灵,像幻觉一样,刚刚还没有呢,重复读取同一条件(where num<=4)的数据,就又出现了。称之为幻读。

使用MySQL的一定注意:MySQL 的默认事务隔离级别就是该REPEATABLE READ级别,但由于MySQL的实现使用了next-Key Lock模式(一种行锁模式,同时锁定某个范围内的全部行和范围,可以参考我的关于MySQL锁的介绍),导致一旦读取了某些条件的数据例如(where num<=4),就会锁定这些记录行以及<=4这个范围,意味着就不能插入3这个数据了。从而避免了幻读的问题。因此对于MySQL来说,使 用REPEATABLE READ级别就达到了消除:脏读,不可重复读,幻读的典型隔离性问题。


SERIALIZABLE,序列化(串行化),指的是事务A在执行时,不允许事务B对数据执行更新操作。

测试如下,恢复初始数据:

session-A,开启serializable隔离级别的事务,但是未提交

— session-A
— 设置隔离级别为 serializable
set transaction isolation level serializable;
start transaction;
— session-A
— 等待session-B提交后执行
select * from kang_tx;

session-B,开启事务,尝试获取和更新数据

— session-B
start transaction;
— 读取内容
select * from kang_tx;
— 更新一条记录
update kang_tx set num=20 where num=2;

结果:

技术分享

session-A,提交事务

— session-A
commit;

session-B,刚刚被阻塞的执行,在事务A提交后,执行了

结果:

技术分享

 

解释:在串行化级别的事务A开启后,添加了锁定,阻塞了所有的其他事务写操作,意味着只有在事务A,提交后,其他事务才能对数据进行写操作。这就是串行化级别。该级别就避免了,脏读,不可重复读,幻读的问题。是最理想的隔离级别。

但是并一定最常用,因为,隔离性理想了,但是为实现隔离性从而的锁开销增大了。因此为了兼顾平衡,较多数据库实现的是:read committed或repeatable read级别。

通常只有在XA分布式事务时,才会使用该级别。关于分布式XA事务,可以参考文章。


来个总结:

技术分享

看完之后,试着回答本文最开头的问题。

一家之言,欢迎拍砖。

韩忠康

任意转载,请保留出处

MySQL事务的隔离级别

标签:

人气教程排行