MybatisPlus扩展实现批量新增与更新

3/1/2023 MP扩展

# MybatisPlus批量操作

  • 使用过Mybatis_Plus的都知道,Mybatis_Plus的批量操作只有在IService才有(saveBatch|saveOrUpdateBatch),且通过源码可以看到,是通过批次以及单条进行操作的
/**
* 执行批量操作
*
* @param entityClass 实体类
* @param log         日志对象
* @param list        数据集合
* @param batchSize   批次大小
* @param consumer    consumer
* @param <E>         T
* @return 操作结果
* @since 3.4.0
*/
public static <E> boolean executeBatch(Class<?> entityClass, Log log, Collection<E> list, int batchSize, BiConsumer<SqlSession, E> consumer) {
    Assert.isFalse(batchSize < 1, "batchSize must not be less than one");
    return !CollectionUtils.isEmpty(list) && executeBatch(entityClass, log, sqlSession -> {
        int size = list.size();
        int idxLimit = Math.min(batchSize, size);
        int i = 1;
        for (E element : list) {
            consumer.accept(sqlSession, element);
            if (i == idxLimit) {
                sqlSession.flushStatements();
                idxLimit = Math.min(idxLimit + batchSize, size);
            }
            i++;
        }
    });
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
  • Mybatis_PlusBaseMapper并没有提供批量方法,所以我们可以自己来扩展一下BaseMapper,使它也拥有批量方法,方便我们在Service层进行业务处理后也能使用批量操作。

# MybatisPlus批量扩展实现

# 自定义批量新增方法

/**
 * @version 1.0.0
 * @className: InsertBatchMethod
 * @description: MP批量新增
 * @author: LiJunYi
 * @create: 2023/2/28 16:22
 */
@Slf4j
public class InsertBatchMethod extends AbstractMethod {

    private static final long serialVersionUID = 2074909358033325037L;

    /**
     * 构造函数
     *
     * @param methodName 方法名称
     */
    protected InsertBatchMethod(String methodName) {
        super(methodName);
    }

    /**
     * 注入自定义 MappedStatement
     *
     * @param mapperClass mapper类
     * @param modelClass  模型类
     * @param tableInfo   表信息
     * @return {@link MappedStatement}
     */
    @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);
        // 第三个参数必须和SuperMapper的自定义方法名一致
        return this.addInsertMappedStatement(mapperClass, modelClass, "insertBatch", sqlSource, new NoKeyGenerator(), null, null);
    }

    /**
     * 表字段信息SQL
     *
     * @param tableInfo 表信息
     * @return {@link String}
     */
    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();
    }

    /**
     * 要新增的数据SQL
     *
     * @param tableInfo 表信息
     * @return {@link String}
     */
    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();
    }
}

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74

# 自定义批量更新方法

/**
 * @version 1.0.0
 * @className: UpdateBatchMethod
 * @description: 批量更新
 * @author: LiJunYi
 * @create: 2023/2/28 16:23
 */
@Slf4j
public class UpdateBatchMethod extends AbstractMethod {

    private static final long serialVersionUID = 8584770698297436989L;

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

    /**
     * 注入自定义 MappedStatement
     *
     * @param mapperClass mapper类
     * @param modelClass  模型类
     * @param tableInfo   表信息
     * @return {@link MappedStatement}
     */
    @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);
        // 第三个参数必须和SuperMapper的自定义方法名一致
        return this.addUpdateMappedStatement(mapperClass, modelClass, "updateBatch", sqlSource);
    }
}

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37

# SQL注入器注入

/**
 * @version 1.0.0
 * @className: CustomizedSqlInjector
 * @description: SQL注入器
 * @author: LiJunYi
 * @create: 2023/2/28 16:25
 */
public class CustomizedSqlInjector extends DefaultSqlInjector {

    /**
     * 如果只需增加方法,保留mybatis plus自带方法,
     * 可以先获取super.getMethodList(),再添加add
     */
    @Override
    public List<AbstractMethod> getMethodList(Class<?> mapperClass, TableInfo tableInfo) {
        List<AbstractMethod> methodList = super.getMethodList(mapperClass,tableInfo);
        methodList.add(new InsertBatchMethod("批量新增方法"));
        methodList.add(new UpdateBatchMethod("批量更新方法"));
        return methodList;
    }
}

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22

# MP配置

@Configuration
@MapperScan("com.xx.module.yy.**.dao")
public class MybatisPlusConfig
{
    @Bean
    public CustomizedSqlInjector customizedSqlInjector() {
        return new CustomizedSqlInjector();
    }
}
1
2
3
4
5
6
7
8
9

# 自定义SuperMapper

  • 注意这个类不要让mp扫描到!!
package com.xx.module.framework.mybatis;

/**
 * @version 1.0.0
 * @className: SuperMapper
 * @description: 注意这个类不要让 mp 扫描到!!
 * @author: LiJunYi
 * @create: 2023/2/28 16:27
 */
public interface SuperMapper<T> extends BaseMapper<T> {

    /**
     * 自定义批量插入
     *
     * @param entityList 实体对象集合
     * @return int
     */
    int insertBatch(@Param("list") Collection<T> entityList);

    /**
     * 自定义批量更新
     *
     * @param entityList 实体对象集合
     * @return int
     */
    int updateBatch(@Param("list") Collection<T> entityList);

}

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29

# IBasicService

/**
 * @version 1.0.0
 * @className: IBasicService
 * @description:
 * @author: LiJunYi
 * @create: 2023/2/28 16:34
 */
public interface IBasicService<T> extends IService<T> {

    /**
     * 批量插入
     * @param entityList 实体对象集合
     * @return int
     */
    int insertBatch(Collection<T> entityList);

    /**
     * 批处理更新
     * @param entityList 实体对象集合
     * @return int
     */
    int updateBatch(Collection<T> entityList);
}

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24

# IBasicService实现类

/**
 * @version 1.0.0
 * @className: BasicServiceImpl( 泛型:M 是 mapper 对象,T 是实体 )
 * @description:
 * @author: LiJunYi
 * @create: 2023/2/28 16:34
 */
public class BasicServiceImpl<M extends SuperMapper<T>, T> extends ServiceImpl<M, T> implements IBasicService<T> {

    /**
     * 批量新增
     *
     * @param entityList 实体对象集合
     * @return int
     */
    @Override
    public int insertBatch(Collection<T> entityList) {
        return baseMapper.insertBatch(entityList);
    }

    /**
     * 批量更新
     *
     * @param entityList 实体对象集合
     * @return int
     */
    @Override
    public int updateBatch(Collection<T> entityList) {
        return baseMapper.updateBatch(entityList);
    }
}

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32

# 如何使用

只需要将原先继承BaseMapper的修改为SuperMapper即可

public interface xxDao extends BaseMapper<xxModel> {}
1
public interface xxDao extends SuperMapper<xxModel> {}
1