在大批量插入数据库的时候,如果用for循环一条条插入效率肯定会异常底下,本文介绍ibatis批量插入是如何做的,我这里使用多线程进行分批插入,一批插入一万条,实际插入交给子线程处理,这样可以节省前端等待时间。在dao层定义个线程池,线程池定义方式以及参数如下
private static ThreadPoolExecutor executor = new ThreadPoolExecutor(1, 2, 10, TimeUnit.MINUTES,new ArrayBlockingQueue<Runnable>(20), new ThreadPoolExecutor.CallerRunsPolicy());
参数说明如下:
int corePoolSize,//核心线程数
int maximumPoolSize,//最大线程数
long keepAliveTime,//线程存活时间
TimeUnit unit,//线程存活时间单位
BlockingQueue<Runnable> workQueue,//阻塞队列
ThreadFactory threadFactory,//线程工厂(创建线程)
RejectedExecutionHandler handler//拒绝策略
核心线程数跟最大线程数有什么区别?
其实就是正式员工跟外包员工的区别一样,当正式员工不够用的时候就去外部借调外包员工,处理完任务之后外包员工可以释放,最终只剩下正式员工。所以设置的时候最大线程数要大于核心线程数。当任务繁忙时,线程最多会创建的数量就是maximumPoolSize。当任务处于空闲时,线程会被回收,最终剩下的线程数就是corePoolSize。
keepAliveTime和TimeUnit控制线程什么时候会被回收,也就是当空闲多久的时候就会销毁部分线程,这里核心跟非核心并没有严格区分,销毁的线程并不是说一定是非核心的,只是最终剩下的数量等于corePoolSize。
@Override
public int batchInsert(List<Record> list) {
if (list.size()>10000){
int num = list.size()/10000;
for (int i = 0; i <= num; i++) {
if (i<num){
MyTask myTask = new MyTask(list.subList(i*(10000),(i+1)*10000));
executor.execute(myTask);
}else if (list.size()%10000 != 0){
MyTask myTask = new MyTask(list.subList(i*(10000),list.size()));
executor.execute(myTask);
}
}
}else {
MyTask myTask = new MyTask(list);
executor.execute(myTask);
}
return 0;
}
public class MyTask implements Runnable {
private List<Record> list;
public MyTask(List<Record> list) {
this.list = list;
}
@Override
public void run() {
getSqlMapClientTemplate().insert("xxxxxxxxx.batchInsert", list);
}
}
XML代码配置格式写法如下
<insert id="batchInsert" parameterClass="java.util.List">
INSERT INTO xxx(batch_no, phone, create_time) VALUES
<iterate conjunction=",">
(
#list[].batchNo#,
#list[].phone#,
#list[].createTime#
)
</iterate >
</insert>
ps:subList方法是左闭右开的,比如说list.subList(0,10),拿到的数据是不包括第10条的,即 0<=n<10。