mysql 进阶 事务隔离级别
最近一段时间闲来无事,写篇文章,算是对大一学习mysql的一个回顾吧
何谓事务 ?他就好比为一个操作单元,这个操作要么执行,要么不执行。例如,我们四条增删查改的sql,归为一个事务,如果这四条sql有一个执行失败则其余三条通通失效(回滚)。当事务执行时也无法被其他事务干扰,也就是说并发时事务是隔离的,互不影响。同时,事务如果执行成功,对数据库将产生持久的影响。
以上介绍就表明了事务的几大特性:
- 原子性
- 隔离性
- 一致性
- 持久性
ok,回到正题,mysql的事务隔离级别如下:
- 序列化:隔离级别最高,同时也是效率最低
- 可重复读:mysql默认隔离级别
- 读提交:
- 读未提交:
读未提交实践
假设我们有如下一张商品表:

| good_id | 商品id | |
| good_num | 商品数量 | |
| good_name | 商品名字 |
首先,通过如下sql查看当前事务隔离级别
SELECT @@GLOBAL.tx_isolation, @@tx_isolation;
查询结果如下图

全局和当前会话的都为可重复读,现在从读未提交开始研究。首先,修改当前会话隔离级别为读未提交
SET SESSION TRANSACTION ISOLATION LEVEL READ UNCOMMITTED
可以看到修改结果如下图

接下来,打开两个窗口,用来表示两个事务。这里的 B窗口我们已经修改成读未提交。
现在,在 A 窗口输入如下语句,但是不执行
START TRANSACTION;
UPDATE goods_info SET good_name = "羊肉"
update goods_info set good_name = "牛肉"
COMMIT;
然后在 B 窗口输入如下语句,但是不执行
START TRANSACTION;
SELECT good_name FROM goods_info
SELECT good_name FROM goods_info
commit;
脏读
- 执行 A B 窗口的第一句(执行顺序无所谓),分别开启事务
- 执行 B 窗口第二句,查询商品名字发现结果如下

- 执行 A窗口的第二句,再执行 B 窗口的第三句,得到查询结果 为 羊肉
由于事务是互不影响的,而此时 B 事务 读取到了 A 事务未提交的数据,那这就就是脏数据, 也叫脏读。
不可重复读
- 执行 A B 窗口的第一句(执行顺序无所谓),分别开启事务
- 执行 B 窗口第二句,查询商品名字发现结果 为 牛肉
- 执行 A窗口的第二句,并提交 A 事务。再执行 B 窗口的第三句,得到查询结果 为 羊肉
这和脏读的本质区别在于:脏读读的是未提交的数据,而不可重复读读取的是其他事务已经提交的数据,(按照隔离性的理论,事务之间是互相不干扰的。)
幻读
看名字就是产生幻觉了。
A 窗口 有如下语句
START TRANSACTION;
insert into goods_info values(”牛肉干“);
commit;
B 窗口 有如下语句
START TRANSACTION;
select * from goods_info
delete from goods_info where good_name = "牛肉干"
commit;
开始测试:
- 执行 A B 窗口的第一句(执行顺序无所谓),分别开启事务
- 执行 A 窗口的第二句,不提交
- 执行 B 窗口的第二句,可以查到 good_name 为 牛肉干 的一条记录
- 执行 B 窗口的第三句,却发现无法删除,(0 条记录被影响)
明明可以查询 牛肉干 的商品,删除的时候却没有,这出现幻觉了。(实际上因为 a 事务 并未提交),好了通过以上介绍,相信大家已经明白了什么是 脏读,不可重复读,幻读
读提交实践
读提交主要是解决了脏读的问题,而不可重复读,幻读则没有得到解决。前两个可以通过上面的测试例子,但是幻读需要换一个新例子。
幻读
A 窗口 有如下语句
START TRANSACTION;
INSERT INTO goods_info VALUES(2,0,0,"牛肉")
commit;
B 窗口 有如下语句
START TRANSACTION;
SELECT * FROM goods_info
INSERT INTO goods_info VALUES(2,0,0,"牛肉")
commit;
开始测试:
-
执行 A B 窗口的第一句(执行顺序无所谓),分别开启事务,然后执行 A 窗口的第二句
-
执行 B 窗口的第二句,结果如下:

-
执行 B窗口的第三句,此时发现锁超时了,明明没有却无法插入,便出现了幻觉
可重复读
是mysql 默认的隔离级别,主要解决了脏读,不可重复读,幻读依旧没有解决。与都提交的测试样例一样,只不过 A 窗口插入一条后,马上提交事务再执行后面的步骤。
序列化(SERIALIZABLE )
SERIALIZABLE 提供了事务之间最大限度的隔离,在这种隔离级别中,事务一个接一个顺序的执行,不会发生脏读、不可重复读以及幻象读问题,最安全。
如果设置当前事务隔离级别为 SERIALIZABLE,那么此时开启其他事务时,就会阻塞,必须等当前事务提交了,其他事务才能开启成功,因此前面的脏读、不可重复读以及幻象读问题这里都不会发生。但是这样的效率极其低下。
总结
给出一张 MySQL 隔离级别的对比图


被折叠的 条评论
为什么被折叠?



