CREATE TABLE `account` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`username` varchar(8) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL,
`balance` int(11) NULL DEFAULT NULL,
PRIMARY KEY (`id`) USING BTREE
)
1.第一个窗口, 第一次查询
mysql> set session transaction isolation level repeatable read;
Query OK, 0 rows affected (0.00 sec)
mysql> set autocommit=0;
Query OK, 0 rows affected (0.00 sec)
mysql> select * from account;
+----+----------+---------+
| id | username | balance |
+----+----------+---------+
| 1 | 22 | 1000 |
| 2 | 22 | 1000 |
| 3 | 22 | 1000 |
| 4 | 22 | 1000 |
| 5 | 22 | 1000 |
| 6 | 22 | 1000 |
| 8 | 111 | 1000 |
+----+----------+---------+
7 rows in set (0.00 sec)
2.第二个窗口, 第一次查询
mysql> set session transaction isolation level repeatable read;
Query OK, 0 rows affected (0.00 sec)
mysql> select * from account;
+----+----------+---------+
| id | username | balance |
+----+----------+---------+
| 1 | 22 | 1000 |
| 2 | 22 | 1000 |
| 3 | 22 | 1000 |
| 4 | 22 | 1000 |
| 5 | 22 | 1000 |
| 6 | 22 | 1000 |
| 8 | 111 | 1000 |
+----+----------+---------+
7 rows in set (0.00 sec)
3.第一个窗口,改变值(全部变成 33 )并提交
mysql> update account set username='33';
Query OK, 7 rows affected (0.00 sec)
Rows matched: 7 Changed: 7 Warnings: 0
mysql> commit;
Query OK, 0 rows affected (0.00 sec)
4.第二个窗口在第一个窗口改变值后,再次查询,发现没有变化
mysql> select * from account;
+----+----------+---------+
| id | username | balance |
+----+----------+---------+
| 1 | 22 | 1000 |
| 2 | 22 | 1000 |
| 3 | 22 | 1000 |
| 4 | 22 | 1000 |
| 5 | 22 | 1000 |
| 6 | 22 | 1000 |
| 8 | 111 | 1000 |
+----+----------+---------+
7 rows in set (0.00 sec)
5.第二个窗口接着提交,然后在查询,发现值已经变化,保证在事务提交前,读取的都是同一个值,解决不可重复读
mysql> commit;
Query OK, 0 rows affected (0.00 sec)
mysql> select * from account;
+----+----------+---------+
| id | username | balance |
+----+----------+---------+
| 1 | 33 | 1000 |
| 2 | 33 | 1000 |
| 3 | 33 | 1000 |
| 4 | 33 | 1000 |
| 5 | 33 | 1000 |
| 6 | 33 | 1000 |
| 8 | 33 | 1000 |
+----+----------+---------+
7 rows in set (0.00 sec)
总结:
事务隔离级别 - 读取未提交 存在 脏读问题
脏读指事务A读取到了事务B更新了但是未提交的数据,然后事务B由于某种错误发生回滚,那么事务A读取到的就是脏数据。
事务隔离级别 - 读取已提交 存在 不可重复读问题
不可重复读就是,有A,B俩事务
B事务进行了一次余额查询结果为1000
这时A事务对这个余额进行了修改,改为500
这时候B事务再去查询,发现余额变为500,这个就是不可重复读
所以为了解决不可重复读,隔离级别就得设置为可重复读Repeated Read。
读取已提交:解决了脏读问题,但是无法做到可重复读,也没办法解决幻读
事务隔离级别 - 可重复读 题 存在 幻读问题
可重复读在提交前,都是读取的同一个值(实际上数据库数据已经被修改了);提交后读取的就是修改后的内容(数据库真实内容)。
可重复读对此基础上,要求A也必须提交事务,才能读取到B修改并提交事务的数据,若A在B修改并提交事务后没有提交事务就去读取,每次的结果都是一样的,但实际B事务已对数据做出成功修改(硬盘中的文件数据以改变),A事务读到的都是备份数据,总感觉出现了幻觉,所以叫幻读!
可重复读:解决不可重复读问题
幻读 VS 不可重复读
幻读重点在于数据是否存在。原本不存在的数据却真实的存在了,这便是幻读。在同一个事务中,第一次读取到结果集和第二次读取到的结果集不同。(对比上面的例子,当B事务INSERT以后,A事务中再进行插入,此次插入相当于一次隐式查询)。引起幻读的原因在于另一个事务进行了INSERT操作。
RR级别下解决幻读问题靠的是锁机制,而不是MVCC机制
不可重复读重点在于数据是否被改变了。在一个事务中对同一条记录进行查询,第一次读取到的数据和第二次读取到的数据不一致,这便是可重复读。引起不可重复读的原因在于另一个事务进行了UPDATE或者是DELETE操作。
简单来说:幻读是说数据的条数发生了变化,原本不存在的数据存在了。不可重复读是说数据的内容发生了变化,原本存在的数据的内容发生了改变。
超深度解析,讲得不错