通过本次的学习,终于搞明白了事务的隔离级别以及脏读幻读等出现的原因,感谢原文作者:明天的地平线。再次博主也记录下学习的过程,以便以后参考
-
首先要明白什么是事务?
-
事务的ACID
-
MySQL的四种隔离级别
隔离级别
|
脏读
|
不可重复度
|
幻读
|
读取未提交的
|
会
|
会
|
会
|
读取提交的
|
不会 |
会 |
会
|
可重读
|
不会
|
不会 |
会
|
可串行化
|
不会
|
不会
|
不会
|
创建表语句:
SET NAMES utf8mb4;
SET FOREIGN_KEY_CHECKS = 0;
-- ----------------------------
-- Table structure for test
-- ----------------------------
DROP TABLE IF EXISTS `test`;
CREATE TABLE `test` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`num` int(11) NOT NULL,
PRIMARY KEY (`id`) USING BTREE
) ENGINE = InnoDB CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci ROW_FORMAT = Dynamic;
-- ----------------------------
-- Records of test
-- ----------------------------
INSERT INTO `test` VALUES (1, 1);
INSERT INTO `test` VALUES (2, 2);
INSERT INTO `test` VALUES (3, 3);
INSERT INTO `test` VALUES (4, 4);
SET FOREIGN_KEY_CHECKS = 1;
查看数据库的隔离级别
show variables like ‘%isolation%‘
设置数据库的隔离级别
set session transaction isolation level Read Uncommitted;
设置数据库的隔离级别为:Read Uncommitted
实验一:读取未提交-Read Uncommitted
前置条件:将数据库的隔离级别设置为read uncomitted;
set session transaction isolation level Read Uncommitted;
第一步:A开启事务:start tracsaction;
第二步:A查询数据:select * from test;

第三步:B开启事务:start transaction;
第四步:B查询数据:select * from test;
第五步:B更新数据:update test set num=10 where id=1;B没有提交事务
第六步:A读取数据----A读取到了B未提交的数据(当前数据库的隔离级别是:Read Uncommitted)
第七步:B回滚数据:rollback;
第八步:B查询数据:select *from test;
第九步:A查询数:select * from test;
结论:事务B更新了数据,但是没有提交,事务A读取到的是B未提交的记录。因为造成脏读。Read Uncommitted是最低的隔离级别
实验二:读取已提交-Read Committed
前置条件:将数据库的隔离级别设置为:Read Committed;
set session transaction isolaction level Read Committed;
第一步:A开始事务:start transaction;
第二步:A查询数据:select *from test;
第三步:B开启事务:start transaction;
第四步:B查询数据:select * from test;
第五步:B更新数据:update test set num=10 where id=1;
第六步:A查询数据:select * from test;
第七步:B提交数据:commit;
第八步:A查询数据:select * from test;
结论:Read Committed 读已提交的隔离级别解决了脏读的问题,但是出现了不可重复读的问题,即事务A在两次查询的结果不一致,因为在两次查询之间事务B更新了一条数据。
读已提交的只允许读取已经提交的记录 ,但是不要求可重复读
实验三:可重读度-Repeatable Read
前置条件:将数据库的级别设置为可重复度
set session transaction isolation level repeatable read;
第一步:A开始事务:start transaction;
第二步:A查询数据:select * from test;
第三步:B开启事务:start transaction;
第四步:B查询数据:select * from test;
第五步:B更新数据:update test set num=10 where id=1;
此时B并没有提交事务
第六步:B查询数据:select * from test;
第七步:A查询数据
结果仍然是之前的结果(因为B事务还没有提交)
第八步:B提交事务:commit;
第九步:A查询数据:select * from test;此时A查询的记过仍然和之前一样
第十步:B插入一条数据并提交事务:inset into test(num) value(4);
第十一步:A查询数据,发现结果还是和之前的一样:select * from test;
第十二步:A提交事务并查询数据
此时发现A查询的数据已经和B查询的结果一致了;
结论:Repeatable Read隔离级别只允许读取已经提交的事务的记录,
实验四:客串行化-Serializable
?前置条件:将数据库的隔离级别设置为可串行化
第一步:A开始事务并查询数据
第二步:B开启事务并insert数据,发现只能等待,并不能执行下去
第三步:A提交事务
第四步:B插入数据
结论:serializable完全锁定字段,若一个事务来操作同一份数据,那么就必须等待,直到前一个事务完成并解除锁为止。是完整的隔离级别,会锁住对应的数据表,因为会导致效率问题。
参考原文链接:
MySQL的四种隔离级别
原文:https://www.cnblogs.com/zyzblogs/p/11375381.html