MySQL 脏读、幻读、不可重复读

1. 脏读、幻读、不可重复读

脏读 :是指事物读取到其他事务没提交的数据

client1 开启事务查询了 id = 1 的数据,然后它跑去做别的事情(未提交),这时 client2对 id = 1 的数据进行了修改,然后他也跑去做别的事情(未提交),这时 client1 回来又查询了 id = 1 的数据,发现被改变了???然后带着疑惑又去做别的事情,client2 那边因为某个原因对 id = 1 的数据进行了回滚(rollback),而 client1 则又又查询了 id = 1 的数据,发现数据又变回来了,这下彻底懵了。client1:???

client1 : begin; # 开启事务

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

client1 :select * from user where id = 1; # 查询 id = 1 的用户

mysql> select * from user where id = 1;
+----+--------+
| id | name   |
+----+--------+
|  1 | 张三   |
+----+--------+
1 row in set (0.00 sec)

client2:begin;

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

client2:update user set name=‘李四’ where id = 1; # 在 client1 没有 commit 时进行修改

mysql> update user set name='李四' where id = 1;
Query OK, 1 row affected (0.00 sec)
Rows matched: 1  Changed: 1  Warnings: 0

client1 :select * from user where id = 1; # 在 client2 没有 commit 或者 rollback 之前再次进行查询

mysql> select * from user where id = 1;
+----+--------+
| id | name   |
+----+--------+
|  1 | 李四   |
+----+--------+
1 row in set (0.00 sec)

client2:rollback;# client2 因为未知原因进行了回滚

mysql> rollback;
Query OK, 0 rows affected (0.11 sec)

client1 :select * from user where id = 1; # 这时 client1 还没有 commit ,但是又拿到了不同的数据。

mysql> select * from user where id = 1;
+----+--------+
| id | name   |
+----+--------+
|  1 | 张三   |
+----+--------+
1 row in set (0.00 sec)

在整个过程当中 client1 都是处于一脸懵逼的状态,为啥每次拿到的数据都是不一样的?啥情况?

幻读 :是指一次事务中前后数据量发生变化,用户产生不可预料的问题

client1 开启事务查询了 user 表所有的数据,之后进行了对表清空的动作,然后跑去做别的事情(未提交),这时,client2 对数据进行了 insert 操作,拍拍屁股走人了,client1 做完其他事情之后回来再次查询表的时候发现表中有有了数据。client1:???

client1 : begin; # 开启事务

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

client1 : select * from user; # 先查看 user 表中的数据。

mysql> select * from user;
+----+--------+
| id | name   |
+----+--------+
|  1 | 李四   |
|  2 | 王五   |
+----+--------+
2 rows in set (0.00 sec)

client1 :delete from user; # 对表进行清空操作

mysql> delete from user;
Query OK, 2 rows affected (0.00 sec)

client2 :begin; # 开启事务

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

client2 :insert into user value(3,‘张三’); # 对 user 表插入一条数据

mysql> insert into user value(3,'张三');
Query OK, 1 row affected (0.14 sec)

client2 :commit; # 提交事务

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

client1 :select * from user; # 再次对自己清空过的 user 表查询。

mysql> select * from user;
+----+--------+
| id | name   |
+----+--------+
|  3 | 张三   |
+----+--------+
1 row in set (0.00 sec)

clien1又懵了。 client1 :???

不可重复读 :是指在同一次事务前后查询不一致的问题

client1 开启事务查询了 id = 1 的数据,然后 client1 去做别的事情(未提交),但是就在它刚走,client2 对这条数据进行了修改,然后 client1 回来查询读取这条数据就会发现数据改变了。client1:???

client1 :begin; # 开启事务

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

client1 :select * from user where id = 1; # 查询 id = 1 的用户

mysql> select * from user where id = 1;
+----+--------+
| id | name   |
+----+--------+
|  1 | 张三   |
+----+--------+
1 row in set (0.00 sec)

client1 : select * from user where id = 2; # client1 查询完 id = 1 的数据之后并没有 commit ,而是去做别的操作,这时 client2 进行了修改

mysql> select * from user where id = 2;
+----+--------+
| id | name   |
+----+--------+
|  2 | 王五   |
+----+--------+
1 row in set (0.00 sec)

client2 :begin; # 开启事务

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

client2 :update user set name=‘李四’ where id = 1; # 修改 id = 1 的数据

mysql> update user set name='李四' where id = 1;
Query OK, 1 row affected (0.35 sec)
Rows matched: 1  Changed: 1  Warnings: 0

client2 :commit; # 提交

mysql> rollback;
Query OK, 0 rows affected (0.11 sec)

client1 :select * from user where id = 1; # 在 client2 进行了修改后 client1 又回来查询,拿到了不一样的数据。

mysql> select * from user where id = 1;
+----+--------+
| id | name   |
+----+--------+
|  1 | 李四   |
+----+--------+
1 row in set (0.00 sec)

这时 client1 又又又懵了,咋又不一样了?????????????????

2. 如何解决问题?答:MySQL 事务隔离级别

Read Uncommitted(读取未提交内容)

在该隔离级别,所有事务都可以看到其他未提交事务的执行结果。读取未提交的数据,也被称之为脏读(Dirty Read)。

Read Committed(读取提交内容)

这是大多数数据库系统的默认隔离级别(但不是MySQL默认的)。它满足了隔离的简单定义:一个事务只能看见已经提交事务所做的改变。这种隔离级别 也支持所谓的不可重复读(Nonrepeatable Read),因为同一事务的其他实例在该实例处理其间可能会有新的commit,所以同一select可能返回不同结果。

Repeatable Read(可重读)(Mysql默认为此项:REPEATABLE-READ)

这是MySQL的默认事务隔离级别,它确保同一事务的多个实例在并发读取数据时,会看到同样的数据行。不过理论上,这会导致另一个棘手的问题:幻读 (Phantom Read)。简单的说,幻读指当用户读取某一范围的数据行时,另一个事务又在该范围内插入了新行,当用户再读取该范围的数据行时,会发现有新的“幻影” 行。InnoDB和Falcon存储引擎通过多版本并发控制(MVCC,Multiversion Concurrency Control)机制解决了该问题。

Serializable(可串行化)

这是最高的隔离级别,它通过强制事务排序,使之不可能相互冲突,从而解决幻读问题。简言之,它是在每个读的数据行上加上共享锁。在这个级别,可能导致大量的超时现象和锁竞争。

3. 总结

可能看完的小伙伴还是有一些不明白的地方,那么在这里总结一下:

  1. 脏读指读取到其他事务正在处理的未提交的数据。
  2. 不可重复度读指并发更新时,另一个事务前后查询相同数据时的数据不符合预期
  3. 幻读指并发新增、删除这种会产生数量变化的操作时,另一个事务前后查询相同数据时的不符合预期
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

龍九^

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值