MyBatis-Plus 实现乐观锁需同时使用 @Version 注解和 OptimisticLockerInnerInterceptor 插件;字段类型限 Integer/Long/int/long,插件配置不可省略,仅 updateById 和带主键 wrapper 的 update 触发,失败抛 OptimisticLockException。

MyBatis-Plus 实现乐观锁,核心是 @Version 注解 + 乐观锁拦截器 二者缺一不可。只加注解不配插件,完全无效。
实体类中正确使用 @Version 注解
在实体类中声明一个数值型版本字段,并标注 @Version:
- 字段类型必须是
Integer、Long、int、long(不支持String、LocalDateTime等) - 建议数据库列设为
NOT NULL DEFAULT 0,避免NULL导致WHERE version = ?恒假 - 示例:
private Integer version;
必须注册 OptimisticLockerInnerInterceptor 插件
MyBatis-Plus 不会自动启用乐观锁逻辑,它依赖拦截器在 SQL 构建阶段注入 WHERE version = #{version} 条件。
- Spring Boot 3.x + MyBatis-Plus 3.5.3+ 必须使用
MybatisPlusInterceptor+OptimisticLockerInnerInterceptor - 废弃的
OptimisticLockerInterceptor(旧版)已移除,继续使用会静默失效 - 配置示例:
public MybatisPlusInterceptor mybatisPlusInterceptor() {
MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
interceptor.addInnerInterceptor(new OptimisticLockerInnerInterceptor());
return interceptor;
}
仅特定更新方式才触发乐观锁
乐观锁不是对所有 update 都生效,只作用于明确携带版本字段的更新路径:
立即学习“Java免费学习笔记(深入)”;
- ✅
mapper.updateById(entity):要求entity.version非 null,且该 entity 是从数据库查出来的(含原始 version 值) - ✅
mapper.update(entity, wrapper):其中entity含 version 值,wrapper必须包含主键条件(如eq("id", id)) - ❌
lambdaUpdate().set(...).eq(...):纯条件拼接,不读取 entity 字段,version 不参与,乐观锁不触发
并发失败后如何处理
当 version 不匹配导致更新失败时,MyBatis-Plus 抛出 OptimisticLockException,不是普通 SQL 异常:
- 可捕获该异常,提示用户“数据已被他人修改”,引导刷新重试
- version 字段值会在成功更新后自动回写为
oldVersion + 1,并同步到 entity 对象中 - 注意:updateById 默认只用主键 + version 做 WHERE 条件,不校验其他字段是否变更


















