乐观锁是一种无锁并发控制策略,核心思想是“乐观地认为并发冲突不常发生”,只在数据提交时检测冲突。Version
机制是其最常用实现方式,适用于读多写少、冲突频率较低的场景(如账户余额更新、库存扣减、状态变更)。
一、 核心原理与流程
-
核心思想:
-
读取数据时,不锁定记录。
-
更新数据时,检查自读取后版本号(或时间戳等)是否被其他事务修改。
-
如果版本号一致,则更新数据并递增版本号。
-
如果版本号不一致,则认为发生冲突,放弃本次更新(通常通过重试或业务逻辑处理)。
-
-
核心组件:
-
版本字段 (
version
): 表中增加一个整型字段(或时间戳字段update_time
),每次成功更新记录时递增(或更新为当前时间)。 -
读取 (
SELECT
): 读取数据时,同时获取当前version
值(old_version
)。 -
更新 (
UPDATE
): 更新时,在WHERE
条件中包含version = old_version
,并SET version = new_version
。
-
二、 关键实现细节与变种
-
版本字段类型选择:
-
整型 (
INT/BIGINT
): 最常用。递增简单高效 (version = version + 1
)。 -
时间戳 (
TIMESTAMP/DATETIME
): 更新时间精确到毫秒/微秒。更新时SET update_time = NOW(3)
(MySQL 5.6.4+ 支持毫秒)。冲突检测粒度更细,但需确保数据库服务器时间同步,且NOW()
函数精度足够。 -
哈希/校验和: 对整行数据计算哈希值作为版本。能检测任意字段的修改,但计算开销较大,且
WHERE
条件可能复杂。较少用。
-
-
UPDATE
语句的原子性:-
关键保障:
UPDATE ... WHERE id=xxx AND version=old_version
是原子的。数据库保证在满足条件的记录上执行更新(包括version = version + 1
)是不可分割的操作。 -
并发安全: 即使多个事务同时执行此
UPDATE
,也只有一个能成功修改version=old_version
的那条记录(如果存在)。其他事务会因条件不匹配而更新 0 行。
-
-
冲突检测 (
affected_rows
):-
affected_rows == 0
的含义:-
乐观锁冲突 (最常见): 其他事务已成功更新了该记录,导致
version
值改变,不再等于old_version
。 -
记录已被删除:
WHERE id=123 AND version=
-
-