更新时间:2022-09-28 08:20:54 来源:极悦 浏览1102次
不可重复读和幻读是什么?极悦小编来告诉大家。
由于很多人容易搞混不可重复读和幻读, 这两者确实非常相似。
但不可重复读主要是说多次读取一条记录, 发现该记录中某些列值被修改过。
而幻读主要是说多次读取一个范围内的记录(包括直接查询所有记录结果或者做聚合统计), 发现结果不一致(标准档案一般指记录增多, 记录的减少应该也算是幻读)。
其实对于幻读, MySQL的InnoDB引擎默认的RR级别已经通过MVCC自动帮我们解决了, 所以该级别下, 你也模拟不出幻读的场景; 退回到 RC 隔离级别的话, 你又容易把幻读和不可重复读搞混淆, 所以这可能就是比较头痛的点吧!
理论上RR级别是无法解决幻读的问题, 但是由于InnoDB引擎的RR级别还使用了MVCC, 所以也就避免了幻读的出现!
MVCC虽然解决了幻读问题, 但严格来说只是解决了部分幻读问题, 接下来进行演示:
1.打开客户端1查看隔离级别及初始数据
mysql> SELECT @@SESSION.tx_isolation;
+------------------------+
| @@SESSION.tx_isolation |
+------------------------+
| REPEATABLE-READ |
+------------------------+
1 row in set (0.00 sec)
mysql> select * from test_transaction;
+----+-----------+-----+--------+--------------------+
| id | user_name | age | gender | desctiption |
+----+-----------+-----+--------+--------------------+
| 1 | 金刚狼 | 127 | 1 | 我有一双铁爪 |
| 2 | 钢铁侠 | 120 | 1 | 我有一身铁甲 |
| 3 | 绿巨人 | 0 | 2 | 我有一身肉 |
+----+-----------+-----+--------+--------------------+
3 rows in set (0.00 sec)
mysql>
2.打开客户端2查看隔离级别及初始数据
mysql> SELECT @@SESSION.tx_isolation;
+------------------------+
| @@SESSION.tx_isolation |
+------------------------+
| REPEATABLE-READ |
+------------------------+
1 row in set (0.00 sec)
mysql> select * from test_transaction;
+----+-----------+-----+--------+--------------------+
| id | user_name | age | gender | desctiption |
+----+-----------+-----+--------+--------------------+
| 1 | 金刚狼 | 127 | 1 | 我有一双铁爪 |
| 2 | 钢铁侠 | 120 | 1 | 我有一身铁甲 |
| 3 | 绿巨人 | 0 | 2 | 我有一身肉 |
+----+-----------+-----+--------+--------------------+
3 rows in set (0.00 sec)
mysql>
3.在客户端2中开启事务, 然后查询数据
mysql> begin;
Query OK, 0 rows affected (0.00 sec)
mysql> select * from test_transaction;
+----+-----------+-----+--------+--------------------+
| id | user_name | age | gender | desctiption |
+----+-----------+-----+--------+--------------------+
| 1 | 金刚狼 | 127 | 1 | 我有一双铁爪 |
| 2 | 钢铁侠 | 120 | 1 | 我有一身铁甲 |
| 3 | 绿巨人 | 0 | 2 | 我有一身肉 |
+----+-----------+-----+--------+--------------------+
3 rows in set (0.00 sec)
mysql>
4.在客户端1中插入一条id为4的新数据 (直接自动提交)
mysql> insert into test_transaction (`id`,`user_name`,`age`,`gender`,`desctiption`) values (4, '死侍', 18, 0, 'A bad boy');
Query OK, 1 row affected (0.00 sec)
mysql> select * from test_transaction;
+----+-----------+-----+--------+--------------------+
| id | user_name | age | gender | desctiption |
+----+-----------+-----+--------+--------------------+
| 1 | 金刚狼 | 127 | 1 | 我有一双铁爪 |
| 2 | 钢铁侠 | 120 | 1 | 我有一身铁甲 |
| 3 | 绿巨人 | 0 | 2 | 我有一身肉 |
| 4 | 死侍 | 18 | 0 | A bad boy |
+----+-----------+-----+--------+--------------------+
4 rows in set (0.00 sec)
mysql>
5.在客户端2事务中再次查询数据, 发现数据没有变化(表示可以重复读, 并且克服了幻读)!! 但是在客户端2事务中插入一条id为4的新数据, 发现提示数据已经存在!
mysql> begin;
Query OK, 0 rows affected (0.00 sec)
mysql> select * from test_transaction;
+----+-----------+-----+--------+--------------------+
| id | user_name | age | gender | desctiption |
+----+-----------+-----+--------+--------------------+
| 1 | 金刚狼 | 127 | 1 | 我有一双铁爪 |
| 2 | 钢铁侠 | 120 | 1 | 我有一身铁甲 |
| 3 | 绿巨人 | 0 | 2 | 我有一身肉 |
+----+-----------+-----+--------+--------------------+
3 rows in set (0.00 sec)
mysql> select * from test_transaction;
+----+-----------+-----+--------+--------------------+
| id | user_name | age | gender | desctiption |
+----+-----------+-----+--------+--------------------+
| 1 | 金刚狼 | 127 | 1 | 我有一双铁爪 |
| 2 | 钢铁侠 | 120 | 1 | 我有一身铁甲 |
| 3 | 绿巨人 | 0 | 2 | 我有一身肉 |
+----+-----------+-----+--------+--------------------+
3 rows in set (0.00 sec)
mysql> insert into test_transaction (`id`,`user_name`,`age`,`gender`,`desctiption`) values (4, '死侍', 18, 0, 'A bad boy');
1062 - Duplicate entry '4' for key 'PRIMARY'
mysql>
//并且, 此时`update/delete`也是可以操作这条在事务中看不到的记录的!
0基础 0学费 15天面授
Java就业班有基础 直达就业
业余时间 高薪转行
Java在职加薪班工作1~3年,加薪神器
工作3~5年,晋升架构
提交申请后,顾问老师会电话与您沟通安排学习