注解实现Mybatis批量操作分页

来源

同事

问题

为了防止每次批量插入/更新的数据量过大,代码里很多地方都是先分页后插入
比如:

        List<List<XXXDO>> partition = Lists.partition(insertList, 500);
        for (List<XXXDO> listPar : partition) {
            XXXDAO.batchInsert(listPar);
        }

这样子,每次都要写分页代码,而且还容易遗忘

解决

  • 使用AOP实现Mybatis批量操作分页
  1. 自定义注解 BatchPartition
@Target({ElementType.METHOD, ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
public @interface BatchPartition {
    /**
     * 自动分批操作每批次的数量;
     * @return
     */
    int count() default INSERT_OR_UPDATE_NUM;
}
  1. 切面,这里只针对单有效List类型入参;参考链接中的实现更加完善,有兴趣可以去下载研究
@Aspect
@Order
@Component
public class BatchPartitionAspect {

    /**
     * 切面配置
     */
    @Pointcut("@annotation(com.dingtalent.salary.client.batchpartition.BatchPartition)")
    public void pointCut() {
    }

    /**
     * 暂时只支持批量List操作,且resultType为int或Integer的sql
     * @param pjp
     * @param batchPartition
     * @return
     * @throws Throwable
     */
    @Around("pointCut() && @annotation(batchPartition)")
    public Object interceptor(ProceedingJoinPoint pjp, BatchPartition batchPartition) throws Throwable {
        //获取被拦截的方法
        Method method = ((MethodSignature) pjp.getSignature()).getMethod();
        //获取被拦截的方法返回值类型
        Class<?> resultType = method.getReturnType();
        //获取被拦截的方法参数
        Object[] args = pjp.getArgs();
        //检查入参和出参
        if (!this.preCheckArgsAndReturnTypes(method, resultType, args)) {
            return pjp.proceed();
        }
        //单入参处理
        if (args.length == 1 && args[0] instanceof List) {
            return this.foreachProceedOfMultiArgs(pjp, args, 0, batchPartition.count());
        }

        return pjp.proceed();
    }

    /**
     * 检查入参和出参是否符合要求
     *
     * @param method
     * @param resultType
     * @param args
     * @return
     * @throws Throwable
     */
    private boolean preCheckArgsAndReturnTypes(Method method, Class<?> resultType, Object[] args) {
        //出参必须为int或者对应的包装类型Integer
        if (!(Integer.class.getName().equals(resultType.getName()) || int.class.getName().equalsIgnoreCase(resultType.getName()))) {
            return false;
        }

        //入参列表长度必须大于0(必须要有参数)
        if (args == null || args.length == 0) {
            return false;
        }

        return true;
    }

    /**
     * 针对单有效List类型入参的关键性批量处理
     *
     * @param pjp
     * @param args
     * @param index
     * @param batchSize
     * @return
     * @throws Throwable
     */
    private Object foreachProceedOfMultiArgs(ProceedingJoinPoint pjp, Object[] args, int index, int batchSize) throws Throwable {
        List<Object> data = (List) args[index];
        //数据长度小于分批长度,不分批处理
        if (data.size() <= batchSize) {
            return pjp.proceed();
        }
        int count = 0;
        List<List<Object>> partition = Lists.partition(data, batchSize);
        for (List<Object> objects : partition) {
            args[index] = objects;
            count += (Integer) pjp.proceed(args);
        }
        return count;
    }
}
  1. 使用注解
    @BatchPartition
    int batchInsert(@Param("list") List<XXXDO> insertList);

参考

https://github.com/washmore/BatchHacker

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
【社区内容提示】社区部分内容疑似由AI辅助生成,浏览时请结合常识与多方信息审慎甄别。
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

相关阅读更多精彩内容

友情链接更多精彩内容