一、背景

  1. 在账户流水表等重要数据更新,每个账户都需要单线程执行,防止无效多线程执行。
  2. MybatisPlus官方并没有针此处场景进行支持

二、 实现方式

  1. 改造queryWrapper新增lock()方法
  2. 在BaseMapper新增通用方法
  3. 最简单使用queryWrapper.last(" for update") !!!

三、环境

<dependency>
	<groupId>com.baomidou</groupId>
	<artifactId>mybatis-plus-boot-starter</artifactId>
	<version>3.2.0</version>
</dependency>

四、注入自定义批量插入sql

因为只需要改造selectOne方法,那直接CV就好

  1. sql模板
public class SelectOneForUpdate extends AbstractMethod {

    private static final String MAPPER_METHOD = "selectOneForUpdate";
    private static final String SQL_TEMPLATE = "<script>%s SELECT %s FROM %s %s %s for update\n</script>";

    @Override
    public MappedStatement injectMappedStatement(Class<?> mapperClass, Class<?> modelClass, TableInfo tableInfo) {
        SqlSource sqlSource = languageDriver.createSqlSource(configuration, String.format(SQL_TEMPLATE,
                sqlFirst(), sqlSelectColumns(tableInfo, true), tableInfo.getTableName(),
                sqlWhereEntityWrapper(true, tableInfo), sqlComment()), modelClass);
        return this.addSelectMappedStatementForTable(mapperClass, MAPPER_METHOD, sqlSource, tableInfo);
    }
}
public class SelectListForUpdate extends AbstractMethod {

    private static final String MAPPER_METHOD = "selectListForUpdate";
    private static final String SQL_TEMPLATE = "<script>%s SELECT %s FROM %s %s %s for update\n</script>";

    @Override
    public MappedStatement injectMappedStatement(Class<?> mapperClass, Class<?> modelClass, TableInfo tableInfo) {
        String sql = String.format(SQL_TEMPLATE, sqlFirst(), sqlSelectColumns(tableInfo, true), tableInfo.getTableName(),
                sqlWhereEntityWrapper(true, tableInfo), sqlComment());
        SqlSource sqlSource = languageDriver.createSqlSource(configuration, sql, modelClass);
        return this.addSelectMappedStatementForTable(mapperClass, MAPPER_METHOD, sqlSource, tableInfo);
    }
}
  1. 注入sql
public class CustomerSqlInjector extends DefaultSqlInjector {

    @Override
    public List<AbstractMethod> getMethodList(Class<?> mapperClass) {
        List<AbstractMethod> methodList = super.getMethodList(mapperClass);
	methodList.add(new SelectOneForUpdate());
	methodList.add(new SelectListForUpdate());
        return methodList;
    }
}
  1. 通用mapper
public interface CommonMapper<T> extends BaseMapper<T> {

    /**
     * 根据 entity 条件,查询一条记录,并锁定
     *
     * @param queryWrapper 实体对象封装操作类(可以为 null)
     */
    T selectOneForUpdate(@Param(Constants.WRAPPER) Wrapper<T> queryWrapper);

	
    /**
     * 根据 entity 条件,查询全部记录,并锁定
     *
     * @param queryWrapper 实体对象封装操作类(可以为 null)
     */
    List<T> selectListForUpdate(@Param(Constants.WRAPPER) Wrapper<T> queryWrapper);
}
  1. 通用Service
public class CommonServiceImpl<M extends CommonMapper<T>, T> extends ServiceImpl<M, T> {

    
    public T getOneForUpdate(Wrapper<T> queryWrapper) {
        return baseMapper.selectOneForUpdate(queryWrapper);
    }
	
	
    public List<T> listForUpdate(Wrapper<T> queryWrapper) {
        return baseMapper.selectListForUpdate(queryWrapper);
    }
}
Logo

为开发者提供学习成长、分享交流、生态实践、资源工具等服务,帮助开发者快速成长。

更多推荐