MySQL資料庫批量插入(Spring Boot+Mybatis)
1 專案需求
從excel中讀取幾萬條記錄,儲存到MySQL資料庫中。因為記憶體中記錄幾萬條,如果直接遍歷所有記錄,迴圈插入資料庫,耗時太長,所以計劃優化插入速度。
目前可供選擇的解決方案如下:
- mybatis的官方寫法
- 利用mysql特性,拼寫insert sql
- 利用spring的事務,直接執行插入操作
因為本專案是SpringBoot框架+MyBatis技術,從技術便捷性和效能綜合考慮,故決定採用第二種方案。
2 批量插入實現
實際上,大資料量插入主要耗時在session的頻繁開啟。因此一起開啟,集中提交會大幅提升資料插入速度。
@Autowired
private SqlSessionTemplate sqlSessionTemplate;//引入bean
public void batchInsert(List<Fenshu> fenshuList, Date current, String tableName, String courseName){
SqlSession session = sqlSessionTemplate.getSqlSessionFactory().openSession(ExecutorType.BATCH, false);//關閉session的自動提交
excelMapper = session.getMapper(ExcelMapper.class);//利用反射生成mapper物件
try {
int i=0;
for (Fenshu fs : fenshuList) {
excelMapper.saveFenshu(tableName, courseName, current, fs.getXuehao(), fs.getShijuanming(), fs.getDenglushijian(), fs.getJiaojuanshijian(),
fs.getShitileixing(), fs.getShitixuhao (), fs.getShititikuhao(), fs.getShitifenzhi(),
fs.getXueshengdefen(), fs.getDatiyongshi());
if (i % 1000 == 0 || i == fenshuList.size()-1) {
//手動每1000個一提交,提交後無法回滾
session.commit();
session.clearCache();//注意,如果沒有這個動作,可能會導致記憶體崩潰。
}
i++;
}
}catch (Exception e) {
//沒有提交的資料可以回滾
session.rollback();
} finally{
session.close();
}
}
下面就幾個底層問題說一下自己的理解:
1 程式碼中的session還是指mybatis的session,用途使用方式應該與MySQL裡面的session一致的,但是session物件還是儲存在web伺服器記憶體而不是資料庫記憶體。因為session本身就是資料庫的客戶端物件,所以可以理解為客戶端物件存在了web伺服器中。
2 本人理解的實現原理應該是這樣的:web伺服器開啟session,此時會新建MySQL資料庫的session,web伺服器裡面的session不斷獲取批量插入物件儲存在web伺服器記憶體,直到session.commit。當commit時,web伺服器裡面的資料庫客戶端物件會把批量資料,傳送給資料庫伺服器,然後資料庫執行批量插入。也就是說,web伺服器記憶體的物件有可能會在斷電後丟失,未能存入資料庫伺服器。
3 MySQL資料庫配置
我們可以在資料庫配置檔案做一些修改進一步提升批量插入效能,配置檔案修改如下:
bulk_insert_buffer_size=120M
Max_allowed_packet=20M
[mysqldump]
Net_buffer_length=2k
bulk_insert_buffer_size
官方手冊解釋如下:
通俗解釋就是說:如果我們需要向一個非空表中插入資料,增加這個快取的大小會提升插入速度。
本專案中,我們修改這個引數,主要是為了改善批量插入大表的效能。
Max_allowed_packet
官方手冊解釋如下:
這個引數決定著客戶端每次向資料庫傳送的包的大小。
本專案中,為防止我們每次提交批量資料,導致發包的大小超過資料庫限制,所以我設定了一個適應我專案的引數大小。
show VARIABLES like '%max_allowed_packet%'
set global max_allowed_packet = 2*1024*1024*10
Net_buffer_length
該處引數主要調整伺服器接收語句長度的大小,測試中對資料庫效能影響不大。