探讨MySql RR事务隔离级别

探讨MySql RR事务隔离级别

明白一些东西

RR解决了什么?

RR解决了脏读的问题(保证了在同一个事务下,多次读取同样的数据的结果是一致的),最大功臣就是MVCC机制。但是这也导致RR级别出现的幻读问题,在特定情况下,还是无法彻底解决,本文指在探讨幻读产生的原因,方便之后在开发过程中,避免可能导致幻读情况发生的操作。

其他事务隔离级别暂不探究,探究使用较多的RR。

幻读

RR幻读主要源头

MySQL 使用了多版本并发控制(MVCC)来处理并发事务。MVCC 允许事务在读取数据时不被其他事务的更新所干扰,但在插入或更新数据时,会进行行级锁的加锁操作,以保证数据的一致性。然而,由于行级锁只能锁定已存在的数据行,无法锁定不存在的数据行。

幻读:假设A事务在读取D范围的记录时,B事务又在D范围内插入新的记录,那么A事务再次读取D范围的记录时,就会出现"幻行"。这是其中一种情况。

说一下MVCC

MVCC只在RR(可重复读),RC(读已提交,不可重复读,一个事务从开启到提交,做的修改操作对其他事务都是不可见的)下工作,RU(读未提交)和串行化下不工作。RU总是读取最新数据,串行化对读取行都加锁。

很多数据库都有实现自己的MVCC,实现机制各有不同;Mysql的MVCC,是通过保存数据在某个时间点的快照来实现的,保证不管事务执行多久,看到的数据都是一致的,类似与时间链,事务开始时间不同,看到的数据也可能不一样。

InnoDB的MVCC,是通过在每行记录后面保存两个隐藏列实现。一个列是行创建时间,一个是行删除时间,

当然这里的时间指的是系统指定的版本号。每开启一个新事务,系统版本号都会递增,事务开始时刻的系统版本号作为事务的版本号,用来和查询的行记录的版本号进行比较。使大多数读操作都可以不用加锁

如何比较:

SELECT:

​ 条件1:查找小于等于当前事务版本号的数据行(早于当前事务创建时间),这样可以保证读取到的行,是已经存在或者事务自己插入或者修改过的。(这里的插入,修改往后面看)

​ 条件2:行的删除版本要么没有定义,要么大于当前事务版本号,这样可以确保读取到的行,在事务开始前没有被删除。

INSERT:

​ 为新插入的行,保存当前的系统版本号作为行版本号;这里就对应上面的SELECT了。

DELETE:

​ 删除的行,保存当前的系统版本号作为行删除版本。

UPDATE:

​ 更新时,保存当前系统版本号作为行版本号,行删除版本。

幻读发生的可能场景
  1. 插入新数据:一个事务在可重复读隔离级别下执行了一个查询,返回一组数据。然后另一个事务插入了符合该查询条件的新数据,并提交了事务。当第一个事务再次执行相同的查询时,会发现多了一条之前不存在的数据,从而产生幻读。
  2. 删除已有数据:一个事务在可重复读隔离级别下执行了一个查询,返回一组数据。然后另一个事务删除了其中的一些数据,并提交了事务。当第一个事务再次执行相同的查询时,会发现之前查询到的数据中有一部分已经被删除了,从而产生幻读。
  3. 修改已有数据:一个事务在可重复读隔离级别下执行了一个查询,返回一组数据。然后另一个事务修改了其中的一些数据,并提交了事务。当第一个事务再次执行相同的查询时,会发现之前查询到的数据发生了变化,从而产生幻读。
间隙锁(锁住一定范围的数据)

间隙锁(Gap Lock)是MySQL中的一种行级锁,用于解决幻读问题。它通常与可重复读或更高的隔离级别一起使用。

间隙锁的作用是锁定一个范围的键值之间的间隙(即不存在的键值范围),防止其他事务在该范围内插入新的数据,从而避免了幻读问题的发生。

事务A:

START TRANSACTION;
SELECT * FROM table WHERE column > 10 AND column < 20 FOR UPDATE;

事务B:

START TRANSACTION;
INSERT INTO table (column) VALUES (15);
COMMIT;

在事务A执行SELECT语句时,它会获取一个范围锁,锁定了 column > 10 and column < 20 的间隙。因此,事务B在该范围内插入数据时会被阻塞,直到事务A释放间隙锁。

幻读能彻底解决吗

.....待补充
我觉得不行…知道啥原因引起的,就可能规避这种风险,造房子的,你还要去生产水泥跟砖头吗?

你可能感兴趣的:(mysql,mysql,adb,android)