这篇我们学习事务隔离级别Read Committed,顾名思义,就是读已提交,一个事务只能看到其他并发的已提交事务所作的修改。很显然,该级别可以解决Read Uncommitted中出现的“脏读“问题。除了Mysql,很多数据库都以Read Committed作为默认的事务隔离级别。
下面通过例子来演示Read Committed解决“脏读”:
1. 小明连接数据库去查询自己本学期的成绩,他设置session(当前连接)的事务隔离级别为Read Committed:
xiaoming> set session transaction isolation level read committed;
Query OK, 0 rows affected (0.00 sec)
xiaoming> select @@tx_isolation;
+----------------+
| @@tx_isolation |
+----------------+
| READ-COMMITTED |
+----------------+
1 row in set (0.00 sec)
2. 就在这个时候,小明的班主任王老师也连接了数据库去登记学生本学期的成绩:
mr.wang> begin;
Query OK, 0 rows affected (0.00 sec)
mr.wang> insert into scores(name,score) values ("xiaoming", 59);
Query OK, 1 row affected (0.00 sec)
3. 当王老师还没有提交事务时,小明刚好开始查询自己的成绩,结果他没查到成绩,因为王老师还没提交:
xiaoming> begin;
Query OK, 0 rows affected (0.00 sec)
xiaoming> select * from scores where name = 'xiaoming';
Empty set (0.00 sec)
4. 小明查成绩之后,王老师发现自己登错了成绩,其实小明考了69分,于是他回滚了当前事务, 并重新录入了小明的正确成绩:
mr.wang> rollback;
Query OK, 0 rows affected (0.00 sec)
mr.wang> begin;
Query OK, 0 rows affected (0.00 sec)
mr.wang> insert into scores(name,score) values ("xiaoming", 69);
Query OK, 1 row affected (0.00 sec)
mr.wang> commit;
Query OK, 0 rows affected (0.00 sec)
5. 接着,小明又查了一次成绩,这次他查到了,他很开心,因为他及格了
xiaoming> select * from scores where name = 'xiaoming';
+----+----------+-------+
| id | name | score |
+----+----------+-------+
| 1 | xiaoming | 69 |
+----+----------+-------+
1 row in set (0.00 sec)
虽然解决了“脏读”问题,但是Read Committed不能保证在一个事务中每次读都能读到相同的数据,因为在每次读数据之后其他并发事务可能会对刚才读到的数据进行修改。就像上面,小明在一次事务中2次读取成绩返回的结果不一样。这也反映出了Read Committed事务隔离级别存在以下问题:
a. 不可重复读, 也即一个事务范围内两个相同的查询却返回了不同数据