(1)打开一个客户端A,并设置当前事务模式为repeatable read,查询表account
(2)在客户端A的事务提交之前,打开另一个客户端B,更新表account并提交(3)在客户端A执行步骤(1)的查询:
(4)执行步骤(1),lilei的balance仍然是400与步骤(1)查询结果一致,没有出现不可重复读的 问题;接着执行update balance = balance - 50 where id = 1,balance没有变成400-50=350,lilei的balance值用的是步骤(2)中的350来算的,所以是300,数据的一致性倒是没有被破坏,这个有点神奇,也许是mysql的特色吧
mysql> select * from account;
±-----±-------±--------+
| id | name | balance |
±-----±-------±--------+
| 1 | lilei | 400 |
| 2 | hanmei | 16000 |
| 3 | lucy | 2400 |
±-----±-------±--------+
3 rows in set (0.00 sec)
mysql> update account set balance = balance - 50 where id = 1;
Query OK, 1 row affected (0.00 sec)
Rows matched: 1 Changed: 1 Warnings: 0
mysql> select * from account;
±-----±-------±--------+
| id | name | balance |
±-----±-------±--------+
| 1 | lilei | 300 |
| 2 | hanmei | 16000 |
| 3 | lucy | 2400 |
±-----±-------±--------+
3 rows in set (0.00 sec)
(5) 在客户端A提交事务,查询表account的初始值
mysql> commit;
Query OK, 0 rows affected (0.00 sec)
mysql> select * from account;
±-----±-
《一线大厂Java面试题解析+后端开发学习笔记+最新架构讲解视频+实战项目源码讲义》
【docs.qq.com/doc/DSmxTbFJ1cmN1R2dB】 完整内容开源分享
------±--------+
| id | name | balance |
±-----±-------±--------+
| 1 | lilei | 300 |
| 2 | hanmei | 16000 |
| 3 | lucy | 2400 |
±-----±-------±--------+
3 rows in set (0.00 sec)
(6)在客户端B开启事务,新增一条数据,其中balance字段值为600,并提交
mysql> start transaction;
Query OK, 0 rows affected (0.00 sec)
mysql> insert into account values(4,‘lily’,600);
Query OK, 1 row affected (0.00 sec)
mysql> commit;
Query OK, 0 rows affected (0.01 sec)
(7) 在客户端A计算balance之和,值为300+16000+2400=18700,没有把客户端B的值算进去,客户端A提交后再计算balance之和,居然变成了19300,这是因为把客户端B的600算进去了 ,站在客户的角度,客户是看不到客户端B的,它会觉得是天下掉馅饼了,多了600块,这就是幻读,站在开发者的角度,数据的 一致性并没有破坏。但是在应用程序中,我们得代码可能会把18700提交给用户了,如果你一定要避免这情况小概率状况的发生,那么就要采取下面要介绍的事务隔离级别“串行化”
mysql> select sum(balance) from account;
±-------------+
| sum(balance) |
±-------------+
| 18700 |
±-------------+
1 row in set (0.00 sec)
mysql> commit;
Query OK, 0 rows affected (0.00 sec)
mysql> select sum(balance) from account;
±-------------+
| sum(balance) |
±-------------+
| 19300 |
±-------------+
1 row in set (0.00 sec)
串行化
(1)打开一个客户端A,并设置当前事务模式为serializable,查询表account的初始值:
mysql> set session transaction isolation level serializable;
Query OK, 0 rows affected (0.00 sec)
mysql> start transaction;
Query OK, 0 rows affected (0.00 sec)
mysql> select * from account;
±-----±-------±--------+
| id | name | balance |
±-----±-------±--------+
| 1 | lilei | 10000 |
| 2 | hanmei | 10000 |
| 3 | lucy | 10000 |
| 4 | lily | 10000 |
±-----±-------±--------+
4 rows in set (0.00 sec)
(2)打开一个客户端B,并设置当前事务模式为serializable,插入一条记录报错,表被锁了插入失败,mysql中事务隔离级别为serializable时会锁表,因此不会出现幻读的情况,这种隔离级别并发性极低,开发中很少会用到。
mysql> set session transaction isolation level serializable;
Query OK, 0 rows affected (0.00 sec)
mysql> start transaction;
Query OK, 0 rows affected (0.00 sec)