一,背景介紹
實際投產過程中,遇到過各種報表或者大數據分析的場景,總不可避免較大量級的數據落庫需求。
二,實現方式
1,事務分割提交
即開啟事務->插庫->每隔一定數目提交一次
2,mybatis的foreach標簽
本質上是將字符串拼接到insert語句的values中
三,say nothing without codes
1,先介紹事務提交方式。上代碼
public int synCustomerByTrans(InputStream inputStreamFromSftp) throws Exception { //獲取文件 String temp = null; int row = 0; //開啟事務 SqlSession sqlSession = transManager.openSession(); try (InputStreamReader isr = new InputStreamReader(inputStreamFromSftp, "GBK"); BufferedReader reader = new BufferedReader(isr);) { ArrayList<Customerinformation> list = new ArrayList<>(2000); while ((temp = reader.readLine()) != null) { //解析數據 Customerinformation ci = utilForFillName.convertToCustomer(temp); if (ci != null) { row++; cbcMapper.addCustomer(ci, sqlSession); } if (row % 2000 == 0) { transManager.commit(sqlSession); } } return row; } catch (Exception e) { e.printStackTrace(); throw new Exception(row + ""); } finally { transManager.close(sqlSession); } }
代碼非常簡單,即先開啟事務,接着循環讀文件,並將解析的對象插入數據庫中,每隔2000條數據提交一次,最后關閉事務,為了代碼簡單,最后關閉事務的時候會嘗試先提交,避免有多余的數據尚未提交
另外mapper里的代碼非常簡單,這里就不貼了。
2,執行效果
此次導入數據為6w,每隔對象86個屬性字段。用時40來分鍾,平均速度約250條/秒
3,batch方式,上代碼
public int synCustomerByBatch(InputStream inputStreamFromSftp) throws Exception { //獲取文件 String temp = null; int row = 0; try (InputStreamReader isr = new InputStreamReader(inputStreamFromSftp, "GBK"); BufferedReader reader = new BufferedReader(isr);) { ArrayList<Customerinformation> list = new ArrayList<>(2000); while ((temp = reader.readLine()) != null) { Customerinformation ci = utilForFillName.convertToCustomer(temp); if (ci != null) { row++; list.add(ci); } if (row % 2000 == 0) { cbcMapper.batchAddCustomer(list); list.clear(); } } cbcMapper.batchAddCustomer(list); return row; } catch (Exception e) { e.printStackTrace(); throw new Exception(row + ""); } }
代碼也很簡單,解析處理的數據先存放在list中,(list指定容量也是減少resize耗時),然后利用mybatis的foreach插入list,代碼比較簡單也就補貼了。
4,執行效果
數據同上,6w條數據,每條數據86個字段,耗時50來秒,對的你沒看錯,50來秒,感覺被狠狠鑿了一下
四,總結
本來以為事務會很快,沒想到批量更快,仔細分析下,事務開啟,設置回滾點等等耗費資源比較大。values方式拼接就好,只是有點浪費空間。實驗也證實了這點。
事務方式占內存大約500M,而后者約占內存800M,使用的時候一定要注意。