注解实现Mybatis批量操作分页

2019-06-01  本文已影响0人  南岩飞雪

来源

同事

问题

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

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

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

解决

  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

上一篇 下一篇

猜你喜欢

热点阅读