MyBatis-Plus 提供了乐观锁和悲观锁的支持,用于处理并发控制,确保数据操作的准确性和一致性。
1. 乐观锁
乐观锁假设大多数情况下不会发生并发冲突,它通过版本号机制来判断数据是否被修改。
-
实现原理:
- 乐观锁的实现原理是基于版本号机制的,版本号通常是一个自增的整数,用于记录数据的版本。
- 在更新数据时,需要先获取当前版本号,更新数据后将版本号加 1。
- 如果更新操作时发现版本号与当前版本号不一致,则认为数据已被修改,更新失败。
Mybatis-Plus 实现:
1.添加@Version注解:在实体类的字段上添加@Version
注解,这个字段通常是一个版本号或时间戳。
public class User {
private Long id;
private String name;
@Version
private Integer version;
// 其他字段...
}
2.使用UpdateById
方法:当使用UpdateById
或Update
方法更新数据时,MyBatis-Plus会自动检查版本号,如果版本号不匹配,更新操作会抛出异常。
User user = userMapper.selectById(userId);
user.setName("newName");
userMapper.updateById(user); // 如果版本号不匹配,会抛出异常
2. 悲观锁
悲观锁假设数据可能会被修改,它在读取数据时就对数据加锁,防止其他线程修改数据。
-
实现原理:
- 使用数据库提供的锁机制,如
for update
或select ... lock in share mode
。 - 在读取数据时,先对数据加锁,防止其他线程修改数据。
- 在更新数据时,由于数据已被锁住,其他线程无法修改数据。
- 使用数据库提供的锁机制,如
-
Mybatis-Plus 实现:
在 MyBatis-Plus 中实现悲观锁,可以在 SQL 语句中使用 for update
或 lock in share mode
。
-
在 Mapper 接口中定义带有锁机制的查询方法使用 ,如
for update
:@Select("SELECT * FROM user WHERE id = #{id} FOR UPDATE") User selectByIdForUpdate(Long id);
-
在业务逻辑中使用该查询方法:在读取数据时加锁,确保后续操作不被其他事务干扰。
User user = userMapper.selectByIdForUpdate(userId); user.setName("newName"); userMapper.updateById(user);
对比
一般来说,乐观锁适用于低到中等并发的系统,其中冲突很少。悲观锁适用于高并发的系统,其中冲突频繁,或者数据完整性非常重要。
乐观锁 | 悲观锁 | |
---|---|---|
假设 | 冲突不会发生 | 冲突将发生 |
锁定 | 无明确锁定 | 独占锁定 |
并发 | 高并发 | 低并发 |
性能 | 较好性能 | 较差性能 |
复杂度 | 简单实现 | 复杂实现 |
一般来说,乐观锁适用