快捷搜索: 王者荣耀 脱发

乐观锁在Mybatis修改中的应用

乐观锁在Mybatis修改中的应用

1.乐观锁的概念

乐观锁假设数据一般情况不会造成冲突,所以在数据进行提交更新的时候,才会正式对数据的冲突与否进行检测,如果冲突,则返回给用户异常信息,让用户决定如何去做。乐观锁适用于读多写少的场景,这样可以提高程序的吞吐量。 乐观锁采取了更加宽松的加锁机制。也是为了避免数据库幻读、业务处理时间过长等原因引起数据处理错误的一种机制,但乐观锁不会刻意使用数据库本身的锁机制,而是依据数据本身来保证数据的正确性。 简单来说,乐观锁主要解决的问题是当要更新一条记录的时候,希望这条记录没有被别人更新。

2.乐观锁的实现

CAS 实现:Java 中java.util.concurrent.atomic包下面的原子变量使用了乐观锁的一种 CAS 实现方式。

版本号控制:一般是在数据表中加上一个数据版本号 version 字段,表示数据被修改的次数。当数据被修改时,version 值会 +1。当线程 A 要更新数据时,在读取数据的同时也会读取 version 值,在提交更新时,若刚才读取到的 version 值与当前数据库中的 version 值相等时才更新,否则重试更新操作,直到更新成功。

具体问题应用

这里我们分析一个可能在项目中遇到的”秒杀“的问题,假如有100个商品或者票在出售,为了能保证每个商品或者票只能被一个人购买,如何保证不会出现超买或者重复卖.此时我们就可以考虑加锁的实现。这里我们就采用版本号控制的方式 注意:我们使用的这种方式针对于小型企业的解决方案,因为数据库本身的性能就是个瓶颈,如果对其并发量超过2000以上的就需要考虑其他的解决方案了

以下是具体的代码测试: 在实体类中定义出version这个字段,在配置类中配置乐观锁的拦截器,在测试类中模拟多个用户同时的修改操作

package com.qcw.domain;

@Data
//@TableName("tb_user")
public class User {
          
   

    //@TableId(type = IdType.ASSIGN_ID)
    private Long id;
    private String name;
    @TableField(value = "pwd",select = false)
    private String password;
    private Integer age;
    private String tel;
    @TableField(exist = false)
    private Integer online;
    //逻辑删除字段,标记当前记录是否被删除
    //@TableLogic(value = "0",delval = "1")
    private Integer deleted;
    @Version
    private Integer version;
}
package com.qcw.config;

@Configuration
public class MpConfig {
          
   

    @Bean
    public MybatisPlusInterceptor mpInterceptor(){
          
   
        //1.定义Mp拦截器
        MybatisPlusInterceptor mpInterceptor = new MybatisPlusInterceptor();
        //2.添加具体拦截器
        mpInterceptor.addInnerInterceptor(new PaginationInnerInterceptor());
        //3.添加乐观锁的拦截器
        mpInterceptor.addInnerInterceptor(new OptimisticLockerInnerInterceptor());

        return mpInterceptor;
    }
}
package com.qcw;

import com.qcw.dao.UserDao;
import com.qcw.domain.User;
import org.junit.jupiter.api.Test;
import org.springframework.boot.test.context.SpringBootTest;

import javax.annotation.Resource;
import java.util.ArrayList;
import java.util.List;

@SpringBootTest
class Mybatisplus03DmlApplicationTests {
          
   

    @Resource
    private UserDao userDao;
    @Test
    void testUpdate(){
          
   
        //1.模拟两个用户的修改
        User user = userDao.selectById(3L); //version=3

        User user2 = userDao.selectById(3L);//version=3

        user2.setName("wlx a");
        userDao.updateById(user2);          //version=4

        user.setName("wlx b");
        userDao.updateById(user);           //到这里version=3的条件不成立
    }
}
经验分享 程序员 微信小程序 职场和发展