1. 程式人生 > >MySQL資料庫批量插入(Spring Boot+Mybatis)

MySQL資料庫批量插入(Spring Boot+Mybatis)

1 專案需求

從excel中讀取幾萬條記錄,儲存到MySQL資料庫中。因為記憶體中記錄幾萬條,如果直接遍歷所有記錄,迴圈插入資料庫,耗時太長,所以計劃優化插入速度。

目前可供選擇的解決方案如下:

  1. mybatis的官方寫法
  2. 利用mysql特性,拼寫insert sql
  3. 利用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

這裡寫圖片描述

該處引數主要調整伺服器接收語句長度的大小,測試中對資料庫效能影響不大。