Skip to content

mybatis批量操作

一、mybatis批量操作


import org.apache.ibatis.session.SqlSession;

/**
 * @Description 批量操作形式化参数接口
 * @Author lcy
 * @Date 2021/5/25 16:31
 */
public interface BatchOperationApi {

@Slf4j
@AllArgsConstructor
@Component
public class BatchService {

    /** SqlSession */
    private final SqlSessionTemplate sqlSessionTemplate;

    /**
     * 批量操作
     * @param consumer 数据库操作
     * @return boolean
     * @author lcy
     * @date 2022/4/8 16:03
     **/
    public boolean batchOperation(Consumer<SqlSession> consumer){
        //获取批量sqlSession对象
        SqlSession sqlSession = sqlSessionTemplate.getSqlSessionFactory().openSession(ExecutorType.BATCH,false);
        try {
            //执行批量操作
            consumer.accept(sqlSession);
            sqlSession.commit();
        } catch (Exception e) {
            sqlSession.rollback();
            log.error("批量操作失败",e);
            return false;
        } finally {
            sqlSession.close();
        }
        return true;
    }

}

二、mybatisplus批量操作

上面的批量操作用于mybatisplus的时候,会出现如果失败了,失败之前的数据不会回滚。mybatisplus通过继承和实现他们的接口,自定义一些批量操作的接口。

**注意:**jdbc默认是不支持批量sql执行的,需要在sql连接上添加&allowMultiQueries=true

三、批量插入方法类

/**
 * TODO
 * @Author lcy
 * @Date 2022/5/23 18:11
 */
@Slf4j
public class InsertBatchMethod extends AbstractMethod {

    public InsertBatchMethod(String methodName){
        super(methodName);
    }

    /**
     * 批量插入数据
     * @param mapperClass mapper的class
     * @param modelClass  实体类的class
     * @param tableInfo   表的信息
     * @return org.apache.ibatis.mapping.MappedStatement
     * @author lcy
     * @date 2022/5/25 10:46
     **/
    @Override
    public MappedStatement injectMappedStatement(Class<?> mapperClass, Class<?> modelClass, TableInfo tableInfo) {
        final String sql = "<script>insert into %s %s values %s</script>";
        final String fieldSql = prepareFieldSql(tableInfo);
        final String valueSql = prepareValuesSql(tableInfo);
        final String sqlResult = String.format(sql, tableInfo.getTableName(), fieldSql, valueSql);
        log.debug("sqlResult----->{}", sqlResult);
        SqlSource sqlSource = languageDriver.createSqlSource(configuration, sqlResult, modelClass);
        // 第三个参数必须和RootMapper的自定义方法名一致
        return this.addInsertMappedStatement(mapperClass, modelClass, "insertBatch", sqlSource, new NoKeyGenerator(), null, null);
    }

    private String prepareFieldSql(TableInfo tableInfo) {
        StringBuilder fieldSql = new StringBuilder();
        fieldSql.append(tableInfo.getKeyColumn()).append(",");
        tableInfo.getFieldList().forEach(x -> {
            fieldSql.append(x.getColumn()).append(",");
        });
        fieldSql.delete(fieldSql.length() - 1, fieldSql.length());
        fieldSql.insert(0, "(");
        fieldSql.append(")");
        return fieldSql.toString();
    }

    private String prepareValuesSql(TableInfo tableInfo) {
        final StringBuilder valueSql = new StringBuilder();
        valueSql.append("<foreach collection=\"list\" item=\"item\" index=\"index\" open=\"(\" separator=\"),(\" close=\")\">");
        valueSql.append("#{item.").append(tableInfo.getKeyProperty()).append("},");
        tableInfo.getFieldList().forEach(x -> valueSql.append("#{item.").append(x.getProperty()).append("},"));
        valueSql.delete(valueSql.length() - 1, valueSql.length());
        valueSql.append("</foreach>");
        return valueSql.toString();
    }
}

四、批量修改方法类

/**
 * 批量更新方法实现,条件为主键,选择性更新
 * @Author lcy
 * @Date 2022/5/23 18:13
 */
@Slf4j
public class UpdateBatchMethod extends AbstractMethod {

    public UpdateBatchMethod(String methodName){
        super(methodName);
    }

    /**
     * 通过mybatis的循环批量更新数据
     * @param mapperClass mapper的class
     * @param modelClass  实体类的class
     * @param tableInfo   表的信息
     * @return org.apache.ibatis.mapping.MappedStatement
     * @author lcy
     * @date 2022/5/25 10:44
     **/
    @Override
    public MappedStatement injectMappedStatement(Class<?> mapperClass,Class<?> modelClass,TableInfo tableInfo){
        String sql = "<script>\n<foreach collection=\"list\" item=\"item\" separator=\";\">\nupdate %s %s where %s=#{%s} %s\n</foreach>\n</script>";
        String additional = tableInfo.isWithVersion() ? tableInfo.getVersionFieldInfo().getVersionOli("item","item.") : "" + tableInfo.getLogicDeleteSql(true,true);
        String setSql = sqlSet(tableInfo.isWithLogicDelete(),false,tableInfo,false,"item","item.");
        String sqlResult = String.format(sql,tableInfo.getTableName(),setSql,tableInfo.getKeyColumn(),"item." + tableInfo.getKeyProperty(),additional);
        log.debug("sqlResult----->{}",sqlResult);
        SqlSource sqlSource = languageDriver.createSqlSource(configuration,sqlResult,modelClass);
        // 第三个参数必须和RootMapper的自定义方法名一致
        return this.addUpdateMappedStatement(mapperClass,modelClass,"updateBatch",sqlSource);
    }

}

五、自定义方法注入器

/**
 * 自定义方法SQL注入器
 * @Author lcy
 * @Date 2022/5/23 18:09
 */
public class CustomizedSqlInjector extends DefaultSqlInjector {

    /**
     * 如果只需增加方法,保留mybatis plus自带方法, 可以先获取super.getMethodList(),再添加add
     * @param mapperClass mapper的class
     * @param tableInfo   表对象
     * @return java.util.List<com.baomidou.mybatisplus.core.injector.AbstractMethod>
     * @author lcy
     * @date 2022/5/23 18:20
     **/
    @Override public List<AbstractMethod> getMethodList(Class<?> mapperClass,TableInfo tableInfo){
        List<AbstractMethod> methodList = super.getMethodList(mapperClass,tableInfo);
        methodList.add(new InsertBatchMethod("insertBatch"));
        methodList.add(new UpdateBatchMethod("updateBatch"));
        return methodList;
    }
}

六、自定义批量mapper

/**
 * 批量操作mapper
 * @Author lcy
 * @Date 2022/5/23 18:11
 */
public interface BatchBaseMapper<T> extends BaseMapper<T> {

    /**
     * 自定义批量插入 如果要自动填充,@Param(xx) xx参数名必须是 list/collection/array 3个的其中之一
     * @param list list集合
     * @return int
     * @author lcy
     * @date 2022/5/23 18:13
     **/
    int insertBatch(@Param("list") List<T> list);

    /**
     * 自定义批量更新,条件为主键 如果要自动填充,@Param(xx) xx参数名必须是 list/collection/array 3个的其中之一
     * @param list list list集合
     * @return int
     * @author lcy
     * @date 2022/5/23 18:13
     **/
    int updateBatch(@Param("list") List<T> list);

}

七、修改配置文件

在mybatisplus配置文件增加

@Configuration
public class MybatisPlusConfiguration {

    // 自定义sql注入器
    @Bean
    public CustomizedSqlInjector customizedSqlInjector(){
        return new CustomizedSqlInjector();
    }

}