Mysql中的幻读现象

先看现象,这里有两个事务,我们假定他们一个是事务A,一个是事务B

这是原本的数据库数据

mysql> select * from account;
+----+------+--------+
| id | name | Money  |
+----+------+--------+
|  1 | 张三 | 3000.3 |
|  2 | 李四 | 1000.0 |
|  4 | 王五 | 3000.0 |
|  8 | zs   | 1919.0 |
|  9 | zs   | 1919.0 |
| 10 | zs   | 1919.0 |
| 11 | zs   | 1919.0 |
+----+------+--------+
7 rows in set (0.00 sec)

我们开启事务A和事务B

首先在事务A上进行查询

mysql> begin;
Query OK, 0 rows affected (0.00 sec)

mysql> select * from account;
+----+------+--------+
| id | name | Money  |
+----+------+--------+
|  1 | 张三 | 3000.3 |
|  2 | 李四 | 1000.0 |
|  4 | 王五 | 3000.0 |
|  8 | zs   | 1919.0 |
|  9 | zs   | 1919.0 |
| 10 | zs   | 1919.0 |
| 11 | zs   | 1919.0 |
+----+------+--------+
7 rows in set (0.00 sec)
mysql> select * from account where name='zs';
+----+------+--------+
| id | name | Money  |
+----+------+--------+
|  8 | zs   | 1919.0 |
|  9 | zs   | 1919.0 |
| 10 | zs   | 1919.0 |
| 11 | zs   | 1919.0 |
+----+------+--------+
4 rows in set (0.00 sec)

此时有4个zs

接下来我们到事务B上进行插入,并且提交事务

mysql> begin;
Query OK, 0 rows affected (0.00 sec)

mysql> insert into account (id,name,Money) values(12,'zs',1919);
Query OK, 1 row affected (0.00 sec)

mysql> commit;
Query OK, 0 rows affected (0.01 sec)

可以看到,我插入了一个id=12的用户,并且提交了事务,此时我们再去事务A进行查询

mysql> select * from account where name='zs';
+----+------+--------+
| id | name | Money  |
+----+------+--------+
|  8 | zs   | 1919.0 |
|  9 | zs   | 1919.0 |
| 10 | zs   | 1919.0 |
| 11 | zs   | 1919.0 |
+----+------+--------+
4 rows in set (0.00 sec)

可以看到 ,id=12的这个用户在事务A中是查询不到的,如果我们此时在事务A中插入一个id=12的用户会怎么样呢?

mysql> insert into account(id,name,Money) values(12,'zs',1919);
ERROR 1062 (23000): Duplicate entry '12' for key 'account.PRIMARY'
mysql> select * from account where name='zs';
+----+------+--------+
| id | name | Money  |
+----+------+--------+
|  8 | zs   | 1919.0 |
|  9 | zs   | 1919.0 |
| 10 | zs   | 1919.0 |
| 11 | zs   | 1919.0 |
+----+------+--------+
4 rows in set (0.00 sec)

此时我们不能插入,用户已经存在了,并且查询的时候,我们并没有发现有这个用户

这种幻读现象是发生在事务隔离级别为可重复读的情况下
所以不可重复读这种隔离级别也不能解决幻读现象
官网有这个解释
The so-called phantom problem occurs within a transaction when the same query produces different sets of rows at different times. For example, if a SELECT is executed twice, but returns a row the second time that was not returned the first time, the row is a “phantom” row.
中文翻译过来就是
当同一查询在不同时间生成不同的行集时,所谓的幻像问题发生在事务中。例如,如果 SELECT 执行了两次,但第二次返回了第一次未返回的行,则该行是“幻像”行。

但是可以看到在不可重复读的事务隔离级别下,这种现象并没有发生,出现的是我们上面所见的那种情况,并没有第二次返回第一次未返回的行这种情况。
也就是说,在innoDB引擎下默认的事务隔离级别(可重复读),不会出现官方说的这种情况。

在可重复读隔离级别下,MVCC机制可以确保同一事务内多次读取同一行数据时,数据的值不会发生变化。如果其他事务对该行数据进行修改或删除操作,当前事务读取的仍是之前的版本,而不会出现新插入或删除的数据行。

读已提交这种事务隔离级别就会出现官方所说的情况
接下来演示这种情况
先修改事务A的事务隔离级别

mysql> set session transaction isolation level read committed;
Query OK, 0 rows affected (0.00 sec)

mysql> select @@transaction_isolation;
+-------------------------+
| @@transaction_isolation |
+-------------------------+
| READ-COMMITTED          |
+-------------------------+
1 row in set (0.00 sec)

还是上面的数据库,开启两个事务A,B

事务A

mysql> begin;
Query OK, 0 rows affected (0.00 sec)

mysql> select * from account where Money>1200;
+----+------+--------+
| id | name | Money  |
+----+------+--------+
|  1 | 张三 | 3000.3 |
|  4 | 王五 | 3000.0 |
|  8 | zs   | 1919.0 |
|  9 | zs   | 1919.0 |
| 10 | zs   | 1919.0 |
| 11 | zs   | 1919.0 |
| 12 | zs   | 1919.0 |
| 13 | zs   | 1919.0 |
| 14 | zs   | 1919.0 |
| 15 | zs   | 1919.0 |
+----+------+--------+

此时事务B增加一个数据

mysql> begin;
Query OK, 0 rows affected (0.00 sec)

mysql> insert into account (id,name,Money) values(16,'zs',1919);
Query OK, 1 row affected (0.00 sec)

mysql> commit;
Query OK, 0 rows affected (0.01 sec)

事务A进行查询

mysql> select * from account where Money>1200;
+----+------+--------+
| id | name | Money  |
+----+------+--------+
|  1 | 张三 | 3000.3 |
|  4 | 王五 | 3000.0 |
|  8 | zs   | 1919.0 |
|  9 | zs   | 1919.0 |
| 10 | zs   | 1919.0 |
| 11 | zs   | 1919.0 |
| 12 | zs   | 1919.0 |
| 13 | zs   | 1919.0 |
| 14 | zs   | 1919.0 |
| 15 | zs   | 1919.0 |
| 16 | zs   | 1919.0 |
+----+------+--------+
11 rows in set (0.00 sec)

可以看到第二次查询查到多的一行了,这是读已提交事务隔离级别下的幻读现象,也符合官方描述的那样

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值