擴展mybatis plus支持for update

一、背景

  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>
	<exclusions>
		<exclusion>
			<groupId>com.baomidou</groupId>
			<artifactId>mybatis-plus-generator</artifactId>
		</exclusion>
	</exclusions>
</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);
    }
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章