脏读

a 夏天 提交于 2019-12-20 05:00:08

测试 READ UNCOMMITTED(读取未提交)的隔离性;

insert into user values(3,'小明',1000);
insert into user values(4,'淘宝店',1000);
select * from user;
+----+-----------+-------+
| id | name      | money |
+----+-----------+-------+
|  1 | a         |   900 |
|  2 | b         |  1100 |
|  3 | 小明      |  1000 |
|  4 | 淘宝店    |  1000 |
+----+-----------+-------+
开启一个事务操作数据
小明在淘宝店买了一个100元的零食
star transaction;
update user set money=money-100 where name='小明';
update user set money=money+100 where name='淘宝店';
淘宝店查询结果
select * from user;
SELECT * FROM user;
+----+-----------+-------+
| id | name      | money |
+----+-----------+-------+
|  1 | a         |   900 |
|  2 | b         |  1100 |
|  3 | 小明      |   900 |
|  4 | 淘宝店    |  1100 |
+----+-----------+-------+
由于小明转账在新开启的事务上进行操作的,而该操作结果可以被其他事务(另一方淘宝店)看见,淘宝店查询结果正确,如果小明在此后rollback,我们看看会发生什么?
小明所在事务
rollback;
此时无论谁,查询会发现
+----+-----------+-------+
| id | name      | money |
+----+-----------+-------+
|  1 | a         |   900 |
|  2 | b         |  1100 |
|  3 | 小明      |  1000 |
|  4 | 淘宝店    |  1000 |
+----+-----------+-------+


这就是所谓的脏读。一个事务读取到另一个事务还未提交的数据。
我们把隔离级别设置为read comitted;

SET GLOBAL TRANSACTION ISOLATION LEVEL READ COMMITTED;
SELECT @@GLOBAL.TRANSACTION_ISOLATION;
+--------------------------------+
| @@GLOBAL.TRANSACTION_ISOLATION |
+--------------------------------+
| READ-COMMITTED                 |
+--------------------------------+

这样再有新事务进来,它就只能查询已经提交过的事务数据了,但对于当前事务来说,它们看到的还是未提交的数据,例如:

正在操作当前事务
START TRANSACTION;
UPDATE user SET MONEY=MONEY-800 where NAME='小明';
UPDATE user SET MONEY=MONEY+800 WHERE NAME='淘宝店';
虽然隔离级别设置为READ committed ,但在当前事务中,它仍看到是数据表中临时改变的数据,而不是真正提交过的数据
SELECT * FROM user;
+----+-----------+-------+
| id | name      | money |
+----+-----------+-------+
|  1 | a         |   900 |
|  2 | b         |  1100 |
|  3 | 小明      |   200 |
|  4 | 淘宝店    |  1800 |
+----+-----------+-------+
--假设此时在远程开启了一个新事务,连接到数据库。
$ mysql -u root -p12345612
--此时远程连接查询到的数据只能是已经提交过的
SELECT * FROM user;
+----+-----------+-------+
| id | name      | money |
+----+-----------+-------+
|  1 | a         |   900 |
|  2 | b         |  1100 |
|  3 | 小明      |  1000 |
|  4 | 淘宝店    |  1000 |
+----+-----------+-------+

但还有这样一个问题,假设一个事务操作数据时,其他事务干扰了这个事务的数据,例如

--校长在查询数据时发现
select * from user;
+----+-----------+-------+
| id | name      | money |
+----+-----------+-------+
|  1 | a         |   900 |
|  2 | b         |  1100 |
|  3 | 小明      |   200 |
|  4 | 淘宝店    |  1800 |
+----+-----------+-------+
--校长在求表money平均值之前,小王做了一个操作
start transaction;
insert into user values(5,'c',100);
commit;
此时表中的真实数据是:
select * from user;
+----+-----------+-------+
| id | name      | money |
+----+-----------+-------+
|  1 | a         |   900 |
|  2 | b         |  1100 |
|  3 | 小明      |  1000 |
|  4 | 淘宝店    |  1000 |
|  5 | c         |   100 |
+----+-----------+-------+

–校长在求平均值时,就不会出现不相符合的情况了

select avg(money) from user;
+------------+
| AVG(money) |
+------------+
|  820.0000  |
+------------+

虽然READ COMMITTED 让我们只能读取到其他事务已经提交的数据,但还会出现一个问题,就是在读取同一个表的数据时,可能发生前后不一致的情况,这被称为不可重复读现象(READ COMMITTED)

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!