遇到一個需求是excel數據導入,一次大概會批量插入幾萬的數據。寫完一測奇慢無比。
於是開始打日志,分析代碼,發現是插入數據庫的時候耗時很長,發現是spring data jpa的原因。
翻看jpa的源碼
@Transactional public <S extends T> List<S> saveAll(Iterable<S> entities) { Assert.notNull(entities, "The given Iterable of entities not be null!"); List<S> result = new ArrayList<S>(); for (S entity : entities) { result.add(save(entity)); } return result; }
這里會循環對每個對象進行save操作,看到這里問題也大概清楚了,多次insert操作。
再看看save操作
1 @Transactional 2 public <S extends T> S save(S entity) { 3 4 if (entityInformation.isNew(entity)) { 5 em.persist(entity); 6 return entity; 7 } else { 8 return em.merge(entity); 9 } 10 }
保存的時候,會對對象做存在性檢查,就是先查一邊,要是不存在才會保存。
優化方案有很多種,但是要從根本上解決這個問題,就要避免jpa 的多次保存和存在性檢查,才能減少數據庫的交互。
最后選用的是spring data jpa和spring jdbc組合使用,jpa大量的寫入就用sprng jdbc。
另外,在數據庫地址上加上
rewriteBatchedStatements=true 開啟批量寫入
因為spring jdbc 和spring boot 的兼容性很好,基本不需要什么配置,另外spring jdbc 的namedParameterJdbcTemplate.batchUpdate對批量插入編寫sql也比較快捷。
優化之后比之前減少90%的時間,看來jpa是真不適合數據量稍大的系統,需要和其他框架配合使用才行。