我又來了,又是百萬數(shù)據(jù)的導(dǎo)入,其實(shí)又是項(xiàng)目中遇到的,那么怎么快速導(dǎo)入呢,因?yàn)槲覀冺?xiàng)目用的是JPA,有時(shí)也使用jdbcTemplate,沒錯(cuò)又是jdbcTemplate。對于這種大數(shù)據(jù)的處理,我們能業(yè)務(wù)代碼方面最基本的能想到的就是塊處理和使用線程。此處可以參考JAVA向Mysql插入億級別數(shù)據(jù)---測評
首先由于我們項(xiàng)目用的是jpa,so我最先也使用的jpa來存數(shù)據(jù),而且最先做的也是批量處理,一次存10000數(shù)據(jù)。在springboot1.5中,jpa的save有兩個(gè)方法,先來看一下源碼:
@NoRepositoryBean
public interface CrudRepository<T, ID extends Serializable> extends Repository<T, ID> {
<S extends T> S save(S var1);
<S extends T> Iterable<S> save(Iterable<S> var1);
}
可以看到save既可以保存一個(gè)實(shí)體,也可以保存多個(gè)實(shí)體,所以我選擇的就是保存多個(gè)實(shí)體,結(jié)果發(fā)現(xiàn)save的速度賊慢,尤其是想存100000條數(shù)據(jù)時(shí)。而如果我save單個(gè)實(shí)體,并開啟多線程,發(fā)現(xiàn)save的效率比批量處理要快點(diǎn),我也是懵了。一開始就這樣存80多萬的數(shù)據(jù)用了N久,具體時(shí)間也沒記錄了。
然后自己就想著用最原生的方法來存一下,就是jdbc,同樣一次存10000條,批量處理。
首先要注意的是:
1.在URL連接時(shí)需要開啟批處理、以及預(yù)編譯
String url = “jdbc:mysql://localhost:3306/cds_credit_rtm_data?rewriteBatched
-Statements=true&useServerPrepStmts=false”;
- PreparedStatement預(yù)處理sql語句必須放在循環(huán)體外
接下來就是常規(guī)的jdbc操作:
//開始總計(jì)時(shí)
long bTime1 = System.currentTimeMillis();
//count=1380271
for (int i=0; i<count; i+=100000){
List<DataToEmployee> list = //todo 每次從數(shù)據(jù)庫獲取10w條
Connection conn = null;
PreparedStatement pstm = null;
try{
//加載jdbc驅(qū)動(dòng)
Class.forName("com.mysql.jdbc.Driver");
//連接mysql
conn = DriverManager.getConnection(url, user, password);
String sql = "....."; //insert語句
//關(guān)閉自動(dòng)提交
// conn.setAutoCommit(false);
//預(yù)編譯sql
pstm = conn.prepareStatement(sql);
if(list!=null && list.size()>0){
long bTime = System.currentTimeMillis();
for(DataToEmployee data : list){
pstm.setString(1,data.getName());
......
pstm.addBatch(); //批量處理
}
pstm.executeBatch();
//關(guān)閉分段計(jì)時(shí)
long eTime = System.currentTimeMillis();
//輸出
System.out.println("成功插入10W條數(shù)據(jù)耗時(shí):"+(eTime-bTime));
}
}
}
//關(guān)閉總計(jì)時(shí)
long eTime1 = System.currentTimeMillis();
//輸出
System.out.println("插入"+count+"數(shù)據(jù)共耗時(shí):"+(eTime1-bTime1));
這里統(tǒng)計(jì)出插入10W條數(shù)據(jù)的時(shí)間一般維持在2s左右,相比之前jpa是有很大的提升
成功插入10W條數(shù)據(jù)耗時(shí):2832
成功插入10W條數(shù)據(jù)耗時(shí):1870
成功插入10W條數(shù)據(jù)耗時(shí):2328
成功插入10W條數(shù)據(jù)耗時(shí):2023
成功插入10W條數(shù)據(jù)耗時(shí):2148
成功插入10W條數(shù)據(jù)耗時(shí):1789
成功插入10W條數(shù)據(jù)耗時(shí):1987
成功插入10W條數(shù)據(jù)耗時(shí):2032
...
jpa在存大量數(shù)據(jù)的時(shí)候,需要進(jìn)行ORM轉(zhuǎn)換,MyBatis也一樣,效率相比jdbc肯定要差點(diǎn),而且在使用jdbc的時(shí)候我就用了單線程,可見兩者之間的差距。