" />
文章

MySQL 幻读问题与 FOR UPDATE

select ... for update的意义是什么,如果采用select ... for update 怎么释放锁。
为什么开启事务begin后
使用select ... for update,没有从快照获取数据呢,出现幻读的问题

SELECT ... FOR UPDATE 是一种用于数据库中加锁的查询方式,它可以在事务中对查询的行加上排他锁(Exclusive Lock),确保其他事务在当前事务提交之前无法对这些行进行修改。这种方式广泛用于事务性场景中,以保证数据的一致性和完整性,尤其是在涉及并发的情况下。

SELECT ... FOR UPDATE 的意义

  • 锁定行:执行 SELECT ... FOR UPDATE 后,查询结果的所有行都会被锁定,直到当前事务提交或回滚。在锁定期间,其他事务无法对这些行进行更新或删除操作。
  • 保证数据一致性:当多个事务并发执行时,通过 FOR UPDATE 可以避免脏读和不可重复读的情况,确保当前事务操作的数据在整个事务过程中保持一致。
  • 避免竞争更新:在并发环境下,通过对查询结果加锁,可以避免多个事务同时更新同一数据行,防止竞争条件的发生。

SELECT ... FOR UPDATE 如何释放锁

在使用 SELECT ... FOR UPDATE 加锁后,锁的释放方式主要有以下几种:

  1. 事务提交:在事务中执行 COMMIT 操作后,MySQL 会自动释放锁。
  2. 事务回滚:执行 ROLLBACK 操作时,MySQL 也会释放锁。
  3. 事务结束:一旦事务结束,所有的锁都会自动释放。

注意:在MySQL中,若使用了自动提交(auto-commit)模式,SELECT ... FOR UPDATE 会立即加锁和解锁,因为每个查询都会作为单独的事务提交。

为什么 SELECT ... FOR UPDATE 在开启事务后不会从快照中获取数据

在开启事务后,SELECT ... FOR UPDATE 不会从快照中获取数据,而是直接访问最新的数据。这是因为:

  • 一致性视图与快照隔离:在MySQL InnoDB中,SELECT 在普通的事务隔离级别下(如可重复读)通常会使用多版本并发控制(MVCC)来创建快照,以确保数据一致性。但是当使用 FOR UPDATE 时,会显式请求对查询行加锁,这种操作会跳过快照读取,而是直接读取最新的数据。
  • 数据的实时性要求:FOR UPDATE 通常用于对数据的进一步更新操作,因此需要直接访问最新的数据,而不是快照数据。否则,可能会基于旧数据进行决策,导致数据的不一致性。
  • 防止幻读:如果在 SELECT ... FOR UPDATE 中仅读取快照数据,其他事务可能会插入新的记录,导致幻读问题。因此,通过加锁读取最新数据并锁定,避免了其他事务的插入操作。

使用 SELECT ... FOR UPDATE 时出现幻读的原因

即使使用了 SELECT ... FOR UPDATE,在某些隔离级别(如 可重复读)中可能会出现幻读现象,因为 FOR UPDATE 锁定的是查询结果中已存在的行,并不会锁定所有可能符合查询条件的行。因此,在这种情况下,其他事务可以插入符合条件的新行,从而导致幻读问题。

解决幻读问题

在MySQL InnoDB存储引擎中,可以通过以下方式解决幻读问题:

  • 使用最高隔离级别:在 可串行化(Serializable) 隔离级别下,MySQL会对整个范围加锁,避免其他事务插入新的记录,从而防止幻读。
  • 间隙锁(Gap Lock):在可重复读隔离级别下,InnoDB 通过间隙锁技术防止幻读。间隙锁会锁定查询范围内的“间隙”,防止其他事务在该范围内插入新的数据。

SELECT ... FOR UPDATE 一般适用于避免并发更新的问题,而在需要严格避免幻读的情况下,可以通过调整事务隔离级别或使用间隙锁等技术来解决。

License:  CC BY 4.0