并行事务会引发什么问题?
MySQL 服务端是允许多个客户端连接的,这意味着 MySQL 会出现同时处理多个事务的情况。
那么在同时处理多个事务的时候,就可能出现脏读(dirty read)、不可重复读(non-repeatable read)、幻读(phantom read)的问题。
接下来,通过举例子给大家说明,这些问题是如何发生的。
脏读
如果一个事务「读到」了另一个「未提交事务修改过的数据」,就意味着发生了「脏读」现象。
不可重复读
在一个事务内多次读取同一个数据,如果出现前后两次读到的数据不一样的情况,就意味着发生了「不可重复读」现象。
幻读
在一个事务内多次查询某个符合查询条件的「记录数量」,如果出现前后两次查询到的记录数量不一样的情况,就意味着发生了「幻读」现象。
事务A:
mysql> start transaction;
Query OK, 0 rows affected (0.00 sec)
mysql> insert into user values(1522158666475192324,'testtt','test','1','test','test',0);
Query OK, 1 row affected (0.00 sec)
mysql> select * from user;
+---------------------+--------------+-------------+------+-----------+--------+--------+
| id | name | phone | sex | id_number | avatar | status |
+---------------------+--------------+-------------+------+-----------+--------+--------+
| 1522158666475192321 | 我是谁??? | 13571761373 | NULL | NULL | NULL | 1 |
| 1522158666475192323 | test | test | 1 | test | test | 0 |
| 1522158666475192324 | testtt | test | 1 | test | test | 0 |
+---------------------+--------------+-------------+------+-----------+--------+--------+
mysql> commit;
事务B:
mysql> start transaction;
mysql> select * from user;
+---------------------+--------------+-------------+------+-----------+--------+--------+
| id | name | phone | sex | id_number | avatar | status |
+---------------------+--------------+-------------+------+-----------+--------+--------+
| 1522158666475192321 | 我是谁??? | 13571761373 | NULL | NULL | NULL | 1 |
| 1522158666475192323 | test | test | 1 | test | test | 0 |
+---------------------+--------------+-------------+------+-----------+--------+--------+
2 rows in set (0.11 sec)
mysql> select * from user for update;
+---------------------+--------------+-------------+------+-----------+--------+--------+
| id | name | phone | sex | id_number | avatar | status |
+---------------------+--------------+-------------+------+-----------+--------+--------+
| 1522158666475192321 | 我是谁??? | 13571761373 | NULL | NULL | NULL | 1 |
| 1522158666475192323 | test | test | 1 | test | test | 0 |
| 1522158666475192324 | testtt | test | 1 | test | test | 0 |
+---------------------+--------------+-------------+------+-----------+--------+--------+
3 rows in set (33.73 sec)
-- 或者
mysql> update user set name = 'up' where id = 1522158666475192324;
Query OK, 1 row affected (0.00 sec)
Rows matched: 1 Changed: 1 Warnings: 0
mysql> select * from user;
+---------------------+--------------+-------------+------+-----------+--------+--------+
| id | name | phone | sex | id_number | avatar | status |
+---------------------+--------------+-------------+------+-----------+--------+--------+
| 1522158666475192321 | 我是谁??? | 13571761373 | NULL | NULL | NULL | 1 |
| 1522158666475192323 | test | test | 1 | test | test | 0 |
| 1522158666475192324 | up | test | 1 | test | test | 0 |
+---------------------+--------------+-------------+------+-----------+--------+--------+
3 rows in set (0.09 sec)
执行顺序:
B:select * from user; -- 结果两条记录
A:insert into user values(); -- 未提交
B:select * from user for update; -- 结果三条记录,查当前(for update)
-- 或
B:update user set name = 'up' where id = 1522158666475192324;
B:select * from user; -- 结果三条记录,因为上条更新语句会先查全表数据
-- 对于事务B来说出现了幻觉,这种现象即为幻读。在同一事务中,相同查询条件记录数不同。