编写mybatis批量处理插件
编写该插件的目的是项目中经常会有一些需要批处理的情况,当然Mysql支持insert() values(),()....,()语法,可以间接达到批量提交的目的。但是在update的时候就不行了。
本插件基于mybatis-3.4.4。实现原理:如果上下文中需要开启批处理,那么我就用BatchExecutor代替原先的SimpleExecutor执行器。 插件实现类:
@Intercepts({@Signature(type = Executor.class, method = "update", args = {MappedStatement.class, Object.class}),
@Signature(type = Executor.class, method = "commit", args = {boolean.class}),
@Signature(type = Executor.class, method = "close", args = {boolean.class})
}
)
public class BatchHelperIntercept implements Interceptor {
private int batchCommit = 0;
@Override
public Object intercept(Invocation invocation) throws Throwable {
Executor target = (Executor)invocation.getTarget();
Method method = invocation.getMethod();
if(StringUtils.equals(method.getName(),"update") && MybatisBatchHelper.needBatch()) {
MappedStatement ms = (MappedStatement)invocation.getArgs()[0];
//需要批量提交
BatchExecutor batchExecutor = MybatisBatchHelper.getBatchExecutor();
if (batchExecutor == null) {
batchExecutor = new BatchExecutor(ms.getConfiguration(), target.getTransaction());
MybatisBatchHelper.setBatchExecutor(batchExecutor);
}
Object resObject = method.invoke(batchExecutor, invocation.getArgs());
MybatisBatchHelper.increment();
if(this.batchCommit > 0 && MybatisBatchHelper.getBatchCommit() == this.batchCommit){
//执行executeBatch
batchExecutor.flushStatements();
}
return resObject;
}
BatchExecutor batchExecutor = MybatisBatchHelper.getBatchExecutor();
boolean hasBatchExecutor = batchExecutor != null;
if(StringUtils.equals(method.getName(),"commit") && hasBatchExecutor){
return method.invoke(batchExecutor, invocation.getArgs());
}
if(StringUtils.equals(method.getName(),"close") && hasBatchExecutor){
MybatisBatchHelper.clear();
return method.invoke(batchExecutor, invocation.getArgs());
}
return method.invoke(target,invocation.getArgs());
}
@Override
public Object plugin(Object target) {
//包装插件
return Plugin.wrap(target,this);
}
@Override
public void setProperties(Properties properties) {
this.batchCommit = Integer.parseInt(properties.getProperty("batchCommit","0"));
}
}
spring-boot2 自动配置类
@Configuration
@ConditionalOnBean({SqlSessionFactory.class})
@EnableConfigurationProperties({MybatisBatchProperties.class})
@AutoConfigureAfter({MybatisAutoConfiguration.class})
public class MybatisBatchAutoConfiguration {
@Autowired
private List<SqlSessionFactory> sqlSessionFactoryList;
@Autowired
private MybatisBatchProperties mybatisBatchProperties;
@PostConstruct
public void addPageInterceptor() {
BatchHelperIntercept interceptor = new BatchHelperIntercept();
Properties properties = mybatisBatchProperties.getProperties();
interceptor.setProperties(properties);
Iterator<SqlSessionFactory> it = this.sqlSessionFactoryList.iterator();
while(it.hasNext()) {
SqlSessionFactory sqlSessionFactory = it.next();
sqlSessionFactory.getConfiguration().addInterceptor(interceptor);
}
}
}
用法
在spring-boot2项目中引用JAR包
<dependency>
<groupId>com.github.liuax</groupId>
<artifactId>mybatis-batch-starter</artifactId>
<version>1.0.0</version>
</dependency>
在需要批量提交的代码开启批处理:
MybatisBatchHelper.startBatch();
测试情况
插入
代码
@Override
public void test1(){
//MybatisBatchHelper.startBatch();
for(int i = 0;i<5000;i++){
OssParseLog log = new OssParseLog();
log.setBatchId(i+"");
log.setCrtTime(new Date());
log.setName("aaaa");
log.setHhmmss("112233");
log.setType("test1");
log.setApp("0001");
baseManagr.insertSelective(log);
}
}
未开启批处理的情况:
2019-05-03 08:27:09.429 DEBUG 11236 --- [ main] c.v.f.b.b.s.m.O.insertSelective : <== Updates: 1
84524:ms
ok
开启批处理的情况:
2019-05-03 09:17:40.355 DEBUG 13036 --- [ main] c.v.f.b.b.s.m.O.insertSelective : ==> Parameters: 4999(String), 112233(String), test1(String), 0001(String), aaaa(String), 2019-05-03 09:17:40.355(Timestamp)
1834:ms
ok
更新
代码
@Override
public void test2() {
MybatisBatchHelper.startBatch();
for(int i = 0;i<5000;i++){
OssParseLog log = new OssParseLog();
log.setBatchId(i+"");
log.setCrtTime(new Date());
log.setName("bbbbb");
log.setHhmmss("112233");
log.setType("test2");
log.setApp("0001");
Example example = Example.builder(OssParseLog.class).andWhere(Sqls.custom()
.andEqualTo("batchId",i+"")).build();
baseManagr.updateSelectiveByExample(log,example);
}
}
未开启批处理的情况:
2019-05-03 09:25:04.431 DEBUG 9224 --- [ main] c.v.f.b.b.s.m.O.updateByExampleSelective : <== Updates: 1
87424:ms
ok
开启批处理的情况:
2019-05-03 09:27:40.063 DEBUG 10984 --- [ main] c.v.f.b.b.s.m.O.updateByExampleSelective : ==> Parameters: 4999(String), 112233(String), test2(String), 0001(String), ccccc(String), 2019-05-03 09:27:40.063(Timestamp), 4999(String)
3744:ms
ok