乐观锁
什么是乐观锁:是针对一些特定问题的解决方案,主要解决丢失更新问题
假如有一条数据同时被两个及以上的人进行修改,这个时候就会产生丢失更新问题。
譬如:小明想修改一条数据的money字段,他看到的money是500,他应该500太少想多加一点,改变成1000,但是小红也想改变money,她因为500太少想少加一点,改成600。小明的修改先发生,他们都是由500进行修改的,按理来说,小红应该是根据小明修改后的1000来修改成600,但是事实不是。这就叫丢失更新。
解决方案:
1悲观锁:某一个进行对一条数据进行操作时,其它人不可以操作这条数据,视为串行操作,他的 效率比较低
2乐观锁:新建一个字段为version,再进行操作时给判断版本号的值,若version一样才可以 操作数据u,否则不行
乐观锁的实现:
如图,在这个表中添加一个version字段,并且在实体类中添加这个属性。
package com.atguigu.mpdemo1010.enitty;
import com.baomidou.mybatisplus.annotation.FieldFill;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableId;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.lang.reflect.Field;
import java.util.Date;
@Data
public class User {
@TableId(type = IdType.ID_WORKER)
private Long id;
private String name;
private long age;
private String email;
@TableField(fill = FieldFill.INSERT)
private Date createTime;
@TableField(fill = FieldFill.INSERT_UPDATE)
private Date updateTime;
private Integer version;//版本号
@Override
public String toString() {
return "User{" +
"id=" + id +
", name='" + name + '\'' +
", age=" + age +
", email='" + email + '\'' +
", createTime=" + createTime +
", updateTime=" + updateTime +
", version=" + version +
'}';
}
}
在实体类中的version属性上添加一个注解:@Version
配置一个乐观锁的插件:
mybatis-plus中提供了spring和springboot的插件配置:
spring:
利用bean来进行配置
springboot:创建这个类,并使用@Bean来实现乐观锁
@Bean
public MybatisPlusInterceptor mybatisPlusInterceptor() {
MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
interceptor.addInnerInterceptor(new OptimisticLockerInnerInterceptor());
return interceptor;
}
如何创建这个插件类:
方法一:直接将这个放到springboot中的启动类中
@MapperScan("com.atguigu.mpdemo1010.mapper")
@SpringBootApplication
public class Mpdemo1010Application {
public static void main(String[] args) {
SpringApplication.run(Mpdemo1010Application.class, args);
}
@Bean
public MybatisPlusInterceptor mybatisPlusInterceptor() {
MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
interceptor.addInnerInterceptor(new OptimisticLockerInnerInterceptor());
return interceptor;
}
}
方法二:我们把这个配置插件放到专门的配置类中,让spring帮我自动管理
package com.atguigu.mpdemo1010.config;
import com.baomidou.mybatisplus.extension.plugins.MybatisPlusInterceptor;
import com.baomidou.mybatisplus.extension.plugins.inner.OptimisticLockerInnerInterceptor;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
public class Mpconfig {
@Bean
public MybatisPlusInterceptor mybatisPlusInterceptor() {
MybatisPlusInterceptor mybatisPlusInterceptor = new MybatisPlusInterceptor();
mybatisPlusInterceptor.addInnerInterceptor(new OptimisticLockerInnerInterceptor());
return mybatisPlusInterceptor;
}
}
测试:
插入一条新的数据,让他再被插入时version自动赋值为1
(自动赋值在mybatis_plus文章中)
mybatis实现自填充
@Test
public void add()
{
User user = new User();
user.setName("titi");
user.setAge(22);
user.setEmail("302064225");
Integer insert = userMapper.insert(user);
System.out.println("insert:"+insert);
}
运行结果:
再通过id进行查询并修改:
@Test
public void testlgs()
{
// 根据id查询
User user = userMapper.selectById("1508710305724223490");
System.out.println("乐观锁:"+user);
Scanner sc = new Scanner(System.in);
sc.nextInt();
user.setName("乐观锁");
user.setAge(11);
Integer row = userMapper.updateById(user);
}
运行结果:
因为我在上面的testlgs方法中添加了输入语句,可以暂停程序的运行,这时我们去强行修改user表中的1508710305724223490为id的数据的version为3,然后再继续运行程序,看一下不同的效果。
运行结果如下:
我们看到他的update是为0的就说明没有数据更新成功,所以他没有更新
我们再看一下数据的库的值,是不是还是我们强行修改后的3