在大批量插入數據庫的時候,如果用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。