返回

避免 MySQL 幻读的技巧

后端







MySQL 幻读问题是指在 RR(可重复读)隔离级别下,一个事务读取数据时,如果其他事务在该事务读取数据过程中提交了数据,那么该事务可能会读取到这些提交的数据,而这些提交的数据在该事务开始时是不存在的,这种现象就称为幻读。

### MySQL 幻读产生的原因
在 MySQL 中,事务的隔离级别决定了事务之间如何处理并发访问。在 RR 隔离级别下,事务在执行过程中,其所看到的数据始终与事务开始时的数据快照一致。因此,如果在事务执行过程中,其他事务提交了数据,那么这些提交的数据对于该事务是不可见的,除非该事务重新读取数据。

幻读产生可能是如下两种情况:
* **只读事务 A 正在读取数据,在它读取期间,写事务 B 提交数据。因为在 RR 隔离级别下,事务 A 在开始时就生成快照,该快照在事务 A 执行期间保持不变,不会因其他事务提交而改变,所以 A 读到 B 事务提交的数据。这是幻读发生的根源。** 
* **在可重复读隔离级别下,因为其事务行为是读取已提交的快照,而不是读取数据库的最新状态,因此该事务无法看到其他事务已提交的数据,所以另一个事务更新了数据,导致在第二次查询时读取到了不同的数据,而产生了幻读。** 

### 避免幻读的技巧
避免幻读问题的出现,可以采取以下几个技巧:

**1. 使用 Serializable 隔离级别** 

Serializable 是最高的隔离级别,它可以防止幻读的发生。在 Serializable 隔离级别下,事务在执行过程中,对数据的所有修改都会被立即写入数据库,并且其他事务只能看到这些修改之后的数据。这意味着,即使其他事务在该事务执行过程中提交了数据,这些提交的数据对于该事务也是不可见的。

**2. 使用 Next-Key Lock** 

Next-Key Lock 是一种行锁,它可以防止其他事务在当前事务读取数据之后在该数据上插入新数据。这意味着,即使其他事务在该事务执行过程中提交了数据,这些提交的数据对于该事务也是不可见的。

**3. 使用 SKIP LOCKED** 

SKIP LOCKED 是一个查询提示,它可以防止当前事务等待被其他事务锁定的数据。这意味着,即使其他事务在该事务执行过程中锁定了数据,该事务也可以继续执行,并且不会被阻塞。

**4. 使用乐观锁** 

乐观锁是一种并发控制机制,它通过使用版本号来检测数据是否被其他事务修改过。如果数据被其他事务修改过,则乐观锁会抛出异常,从而阻止该事务提交。

**5. 避免在事务中使用长时间的查询** 

长时间的查询可能会导致其他事务在该事务执行过程中提交数据,从而导致幻读的发生。因此,应避免在事务中使用长时间的查询。

**6. 使用游标来读取数据** 

使用游标来读取数据可以防止其他事务在该事务读取数据过程中提交数据,从而导致幻读的发生。

以上是避免 MySQL 幻读的技巧,希望对您有所帮助。