写在前面:各位看到此博客的小伙伴,如有不对的地方请及时通过私信我或者评论此博客的方式指出,以免误人子弟。多谢!
乐观锁的使用也是很简单的,官网也说的很明确,照搬过来把官网的说明:
使用乐观锁的意图是什么呢?---当要更新一条记录的时候,希望这条记录没有被别人更新。
乐观锁实现方式:
- 取出记录时,获取当前version
- 更新时,带上这个version
- 执行更新时, set version = newVersion where version = oldVersion
- 如果version不对,就更新失败
之上是官网对于乐观锁插件的使用,说到乐观锁顺便说下什么是悲观锁,它们该怎么理解呢,其实就是字面意思:
乐观锁 : 故名思意十分乐观,它总是认为不会出现问题,无论干什么不去上锁!如果出现了问题,再次更新值测试
悲观锁 : 故名思意十分悲观,它总是认为会出现问题,无论干什么都会先上锁!再去操作!
贴代码前先将使用步骤贴一下:
乐观锁插件的使用:
- 数据库增加字段version 我设为为int类型 给它一个默认值1
- User实体增加相应属性 并用@Version注解标识
- MybatisPlusConfig中增加乐观锁插件
建表语句省略了,User类中加属性并用@Version注解标记:
@Version
private int version;
MybatisPlusConfig配置类中添加乐观锁插件:
@Bean
public MybatisPlusInterceptor mybatisPlusInterceptor(){
MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
// 分页插件
interceptor.addInnerInterceptor(new PaginationInnerInterceptor(DbType.MYSQL));
// 乐观锁插件
interceptor.addInnerInterceptor(new OptimisticLockerInnerInterceptor());
return interceptor;
}
当然你也可以按照官网说的方式添加插件。
新建测试类OptimisticLockerTest,先测试一下更新时是否version的值会改变吧:
@SpringBootTest
@RunWith(SpringRunner.class)
public class OptimisticLockerTest {
@Autowired
private UserMapper userMapper;
@Test
public void test() {
User user = userMapper.selectById(1);
user.setUserName("lisi");
userMapper.updateById(user);
}
}
执行结果如下:
如上:名字已经改为lisi,version也加变为了2,更新是没问题,我们使用乐观锁的目的是保证数据安全,当要更新一条记录的时候,希望这条记录没有被别人更新,测试下是否实现了想要的功能呢?新增以下测试方法:
@Test
public void test1(){
User user1 = userMapper.selectById(5);
user1.setUserName("zhaoliu1");
User user2 = userMapper.selectById(5);
user2.setUserName("zhaoliu2");
userMapper.updateById(user2);
userMapper.updateById(user1);
}
如上:测试方法中,我执行了两次更新用户信息的操作,可以理解为两个线程执行更新操作,线程2插队了,先于线程1执行,那么线程1更新就会失败,不加乐观锁的时候值会被线程1再次覆盖,正常执行结果应该是用户名为zhaoliu1,加上客观所后我们期望值为zhaoliu2,,按照官方文档上对于乐观锁的实现方式的解释描述一下这个测试方法:
- 先进行了两次查询 假设获取到的version都为1
- 但是先执行的更新user2对象 此时更新后version变为2
- 当执行更新user1时 where条件where version = oldVersion 没有匹配到 因为这时数据库中的version已经为2 那么就更新失败了
看下执行结果:
如上:id为5的用户名字被改为了zhaoliu2并且version字段也变为了2,达到了预期的效果。
对于乐观锁,有个点需要注意下,官方文档也有说明:
它说仅支持 updateById(id) 与 update(entity, wrapper) 方法,咱自定义一个根据用户名修改年龄的方法:
void updateAgeByUserName(String userName);
UserMapper.xml中增加:
<update id="updateAgeByUserName" parameterType="java.lang.String">
update t_user set age = 30 where user_name = #{userName}
</update>
新增测试方法:
@Test
public void testCustomMethod() {
userMapper.updateAgeByUserName("lisi");
}
从执行结果上看:自定义的这个方法可以正常执行,将年龄修改为30,但version没变,乐观锁失效,即会更新数据但是where条件中没有version。
看下控制台打印的语句:
完毕!