还傻傻搞不懂MySQL事务隔离级别么(图文并茂,保证你懂!)原创
-
一、并行事务会有什么问题? 1.1 脏写 -
1.2 脏读 -
1.3 不可重复读 -
1.4 幻读 1.5 区别 二、事务隔离级别 2.1 读未提交 2.2 读已提交 2.3 可重复读 2.4 串行化 三、结语
一、并行事务会有什么问题?
1.1 脏写
CREATE TABLE `bank_balance` (
`id` int NOT NULL AUTO_INCREMENT,
`user_name` varchar(45) NOT NULL COMMENT '用户名',
`balance` int NOT NULL DEFAULT '0' COMMENT '余额,单位:人民币分,比如100表示人民币1元,默认是0',
`wealth` tinyint NOT NULL DEFAULT '0' COMMENT '富有程度,0:贫穷,1:富有',
PRIMARY KEY (`id`),
UNIQUE KEY `idx_bank_balance_user_name` (`user_name`)
) ENGINE=InnoDB AUTO_INCREMENT=4 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci
mysql> select id,user_name,balance from bank_balance where user_name = 'Tom';
+----+-----------+---------+
| id | user_name | balance |
+----+-----------+---------+
| 3 | Tom | 100 |
+----+-----------+---------+
1 row in set (0.00 sec)
1.2 脏读
脏读(dirty read),指的是读到了其他事务未提交的数据,未提交意味着可能会回滚,也就是可能最终不会持久化到数据库中。其他事务读到了不会持久化的数据,这就是脏读。
比如下图,如果事务A在①处发生回滚,那么事务B在②处使用的Tom余额值200就是一个过期值,这种就是典型的脏读现象。
1.3 不可重复读
%3CmxGraphModel%3E%3Croot%3E%3CmxCell%20id%3D%220%22%2F%3E%3CmxCell%20id%3D%221%22%20parent%3D%220%22%2F%3E%3CmxCell%20id%3D%222%22%20value%3D%22%E2%91%A0%22%20style%3D%22text%3Bhtml%3D1%3BstrokeColor%3D%23B20000%3BfillColor%3D%23e51400%3Balign%3Dcenter%3BverticalAlign%3Dmiddle%3BwhiteSpace%3Dwrap%3Brounded%3D0%3BfontSize%3D20%3BfontFamily%3DArchitects%20Daughter%3BfontColor%3D%23ffffff%3B%22%20vertex%3D%221%22%20parent%3D%221%22%3E%3CmxGeometry%20x%3D%22680%22%20y%3D%22147%22%20width%3D%2252%22%20height%3D%2224%22%20as%3D%22geometry%22%2F%3E%3C%2FmxCell%3E%3C%2Froot%3E%3C%2FmxGraphModel%不可重复读(non-repeatable read),指的是在同一事务内,相同数据在不同的时刻被读到了不一样的值,它和脏读不一样,脏读是指读取到了其他事务未提交的数据,而不可重复读表示读到了其他事务修改并提交后的值。
比如有两个事务,事务A和事务B,事务A查询Tom账户余额是100,事务B查询Tom账户余额也是100。
接下来,事务A把Tom账户余额更新为200,并提交事务。
当事务B继续读取Tom账户余额的时候,发现Tom账户余额是200了,和之前读取到的不一致,对于事务B而言,这种一个事务内多次读取得到不一样值的现象就称为不可重复读现象。
1.4 幻读
%3CmxGraphModel%3E%3Croot%3E%3CmxCell%20id%3D%220%22%2F%3E%3CmxCell%20id%3D%221%22%20parent%3D%220%22%2F%3E%3CmxCell%20id%3D%222%22%20value%3D%22%E2%91%A0%22%20style%3D%22text%3Bhtml%3D1%3BstrokeColor%3D%23B20000%3BfillColor%3D%23e51400%3Balign%3Dcenter%3BverticalAlign%3Dmiddle%3BwhiteSpace%3Dwrap%3Brounded%3D0%3BfontSize%3D20%3BfontFamily%3DArchitects%20Daughter%3BfontColor%3D%23ffffff%3B%22%20vertex%3D%221%22%20parent%3D%221%22%3E%3CmxGeometry%20x%3D%22680%22%20y%3D%22147%22%20width%3D%2252%22%20height%3D%2224%22%20as%3D%22geometry%22%2F%3E%3C%2FmxCell%3E%3C%2Froot%3E%3C%2FmxGraphModel幻读(phantom read),主要是是针对数据插入(INSERT)和删除(DELETE)操作来说的。
最经典的是插入的情况。假如现在有两个事务,事务A和事务B。事务A对某些行的内容作了更改,但是还未提交。
比如现在余额表中余额大于0的账户有2条,分别是小克和Tom,他们的富有程度都是贫穷:
mysql> select *from bank_balance where balance > 0;
+----+-----------+-----------+--------+
| id | user_name | balance | wealth |
+----+-----------+-----------+--------+
| 2 | 小克 | 300000000 | 0 |
| 3 | Tom | 100 | 0 |
+----+-----------+-----------+--------+
然后,接到上级命令,要把所有账户余额大于0的用户全部标识为富有,启动事务A完成这项任务,SQL如下:
update bank_balance set wealth = 1 where balance > 0;
SQL语句只是执行了,但是未提交。
紧接着,事务B插入了一条余额大于0的记录行(富有程度默认为贫穷),并且在事务A提交之前先提交了,SQL如下:
INSERT INTO `bank_balance` (`id`, `user_name`, `balance`) VALUES ('4', 'Eric', '500');
在这之后,如果事务A再发起相同条件的查询,会发现刚刚的更改对于某些数据未起作用(有些记录未被标识为富有),而且数据行比原来还多了!
这对于事务A而言,感觉出现了幻觉一样,这就是幻读现象。
1.5 区别
读到这里,可能有些小伙伴就懵了,从脏读到幻读,感觉它们都一样的呀?其实,它们有实质性的区别:
1、脏读重在指一个事务读到了其他事务未提交的数据。
2、不可重复读主要在于一个事务中多次读到同一条数据,但前后读到的结果不一样,这是因为其他事务对数据进行修改并提交导致。
3、幻读则是因为被其他事务插入或者删除的数据影响,一个事务内同样条件的数据记录变多或者变少了。
二、事务隔离级别
1. 读未提交(READ UNCOMMITTED),指一个事务还没提交,它做的修改就能被其他事务看到。
2. 读提交(READ COMMITTED),一个事务做的修改,只有提交之后,其他事务才能看到。
3. 可重复读(REPEATABLE READ),在整个事务过程中看到的数据,自始至终都是一致的。
4. 串行化(SERIALIZABLE),每个读写操作都会加锁,多个事务要访问同一条记录时,必须要进行排队,优先级低的事务必须等优先级高的事务完成以后才能进行。
结语
我是tin,一个在努力让自己变得更优秀的普通工程师。自己阅历有限、学识浅薄,如有发现文章不妥之处,非常欢迎加我提出,我一定细心推敲并加以修改。
本文首发于公众号【看点代码再上班】,欢迎围观,第一时间获取最新文章。