【MySQL】MySQL事务的问题:脏读、幻读、不可重复读

MySQL事务的问题:脏读、幻读、不可重复读

在上一篇文章中,我们已经学习过了事务相关的基础知识,今天,我们继续学习事务有可能带来的一些问题。其实在一次请求和连接中,事务是不会出现什么问题的,毕竟在一个事务中,要么全提交,要么全回滚。但是如果有多个客户端连接,也就是说在并发操作事务的情况下,就会发生各种问题。其中最典型的就是下面三种情况,不过首先我们设置一下事务隔离级别,这个东西我们下次再讲,这回我们先把事务隔离级别设置为最低的级别。

-- my.cnf
[server]
transaction-isolation = READ-UNCOMMITTED

脏读

脏读的意思就是两个事务同时在运行,其中 A 事务修改了某个字段,B 事务读取了这个字段,这时可能因为某种原因,A 事务的修改操作回滚了,那么 B 读取的数据就是不正确的,也就是说,B 读到的数据是 “脏” 的。

-- 事务 A
mysql> begin;
Query OK, 0 rows affected (0.00 sec)

mysql> update test_user set username = 'aaa' where id = 2199993;
Query OK, 1 row affected (0.00 sec)
Rows matched: 1  Changed: 1  Warnings: 0

-- 事务 B
mysql> begin;
Query OK, 0 rows affected (0.00 sec)

mysql> select username from test_user where id = 2199993;
+----------+
| username |
+----------+
| aaa      |
+----------+
1 row in set (0.00 sec)

在这个例子中,事务 A 没有提交,但事务 B 读取到的依然是修改之后的数据,之后如果事务 A 回滚或者再次修改成别的数据,那么 B 那边之前读取到的数据就一直是有问题的。

更加典型的例子是,假如我们修改的是你帐户里余额,本身余额有 100 块,第一笔交易将余额修改成了 80 块,这时第二个交易事务过来,读到了你的余额是 80 块,然后又扣了 10 块钱,正常情况下你的余额应该是 70 块了。但是,注意,第一笔交易的事务出现问题了,无法正常继续交易,于是回滚成 100 块。然而第二笔交易的事务并不知情,依然正常交易并提交了,这时你的余额就变成了 70 元。很明显,这就产生了问题,这个就是脏读带来的结果,一致性出现了问题。

不可重复读

不可重复读是啥意思呢?其实跟上面的是一样概念,只是说我们的 B 事务之后又读了一次 A 事务已经提交的数据,发现两次数据不对呀,这就是不可重复读。官方一点的解释就是:A 事务修改了数据,B 事务在修改前和修改后读取的数据不一样。注意,在不可重复读中,没有回滚的操作,另外,如果两个事务同时都是修改一条数据的话,那么后修改的数据会覆盖前面修改事务的操作结果,这也是不可重复读的问题。

-- 事务B
mysql> begin;
Query OK, 0 rows affected (0.00 sec)

mysql> select username from test_user where id = 2199993;
+----------------------+
| username             |
+----------------------+
| 355607b664269a13dae9 |
+----------------------+
1 row in set (0.00 sec)

-- 事务A
mysql> begin;
Query OK, 0 rows affected (0.00 sec)

mysql> update test_user set username = 'aaa' where id = 2199993;
Query OK, 1 row affected (0.00 sec)
Rows matched: 1  Changed: 1  Warnings: 0

mysql> commit;
Query OK, 1 row affected (0.00 sec)

-- 事务B
mysql> select username from test_user where id = 2199993;
+----------+
| username |
+----------+
| aaa      |
+----------+
1 row in set (0.00 sec)

幻读

最后一个幻读,其实它和前面两个问题的情况也是类似的,都是读取的不一致问题,并且和不可重复读非常类似。当 B 事务读取数据时使用的是聚合方式,比如说查询数量,那么假设 A 事务在 B 事务第一次读取后增加或者删除了数据,那么 B 事务第二次读取的时候这个数量就会发生变化,就好像产生幻觉了一样。

-- 事务B第一次读取
mysql> begin;
Query OK, 0 rows affected (0.00 sec)

mysql> select count(*) from test_user;
+----------+
| count(*) |
+----------+
|  2200001 |
+----------+
1 row in set (0.49 sec)

-- 事务A删除
mysql> begin;
Query OK, 0 rows affected (0.00 sec)

mysql> delete from test_user where id < 10;
Query OK, 9 rows affected (0.00 sec)

-- 事务B再次读取
mysql> select count(*) from test_user;
+----------+
| count(*) |
+----------+
|  2199992 |
+----------+
1 row in set (0.37 sec)

咋一看,幻读和不可重复读貌似是一个意思呀?确实,它们非常类似,但是,幻读更强调的是聚合操作结果,而不是单一一条数据的修改,这就是它们两个之间最本质的区别。

总结

好了,问题呈现在眼前了,其实大家应该能看出,事务常见的这三个问题都和数据的一致性读取有关,也就是说,在多个并发事务的前提下,如何保证数据的并发一致性就是我们要面对的问题。那么这些问题是怎么解决的呢?这个就是我们下回要讲到的内容了,也就是 事务隔离 机制相关的知识。

  • 4
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
脏读是指一个事务可以读取到另一个事务未提交的数据。不可重复读是指在一个事务内多次读取同一数据时,由于其他事务的修改导致每次读取的结果不一致。幻读是指在一个事务内多次执行相同的查询,由于其他事务的插入或删除导致每次查询的结果不一致。 在MySQL中,事务隔离级别对应的脏读不可重复读幻读的情况如下: - 读未提交(READ UNCOMMITTED)级别下存在脏读不可重复读幻读问题。 - 读已提交(READ COMMITTED)级别下不存在脏读问题,但仍可能存在不可重复读幻读问题。 - 可重复读(REPEATABLE READ)级别下不存在脏读不可重复读问题,但仍可能存在幻读问题。 - 串行化(SERIALIZABLE)级别下不存在脏读不可重复读幻读问题。 因此,在MySQL中,脏读不可重复读幻读都是与事务隔离级别密切相关的读一致性问题。根据需求和业务场景,可以选择合适的事务隔离级别来解决这些问题。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* [Mysql-详解脏读不可重复读幻读](https://blog.csdn.net/ahuangqingfeng/article/details/124407846)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 50%"] - *2* *3* [一文搞懂MySQL脏读,幻读不可重复读](https://blog.csdn.net/liuqinhou/article/details/126360614)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 50%"] [ .reference_list ]
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值