来源
同事
问题
为了防止每次批量插入/更新的数据量过大,代码里很多地方都是先分页后插入
比如:
List<List<XXXDO>> partition = Lists.partition(insertList, 500);
for (List<XXXDO> listPar : partition) {
XXXDAO.batchInsert(listPar);
}
这样子,每次都要写分页代码,而且还容易遗忘
解决
- 使用AOP实现Mybatis批量操作分页
- 自定义注解 BatchPartition
@Target({ElementType.METHOD, ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
public @interface BatchPartition {
/**
* 自动分批操作每批次的数量;
* @return
*/
int count() default INSERT_OR_UPDATE_NUM;
}
- 切面,这里只针对单有效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;
}
}
- 使用注解
@BatchPartition
int batchInsert(@Param("list") List<XXXDO> insertList);