一、背景
- 在账户流水表等重要数据更新,每个账户都需要单线程执行,防止无效多线程执行。
- MybatisPlus官方并没有针此处场景进行支持
二、 实现方式
- 改造queryWrapper新增lock()方法
- 在BaseMapper新增通用方法
- 最简单使用queryWrapper.last(" for update") !!!
三、环境
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-boot-starter</artifactId>
<version>3.2.0</version>
</dependency>
四、注入自定义批量插入sql
因为只需要改造selectOne
方法,那直接CV就好
- 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);
}
}
- 注入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;
}
}
- 通用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);
}
- 通用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);
}
}