一、背景
- 在賬戶流水錶等重要數據更新,每個賬戶都需要單線程執行,防止無效多線程執行。
- MybatisPlus官方並沒有針此處場景進行支持
二、 實現方式
- 改造queryWrapper新增lock()方法
- 在BaseMapper新增通用方法
- 最簡單使用queryWrapper.last(" for update") !!!
三、環境
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-boot-starter</artifactId>
<version>3.2.0</version>
<exclusions>
<exclusion>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-generator</artifactId>
</exclusion>
</exclusions>
</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);
}
}