Mybatis?大數(shù)據(jù)量批量寫優(yōu)化的案例詳解
Mybatis 大數(shù)據(jù)量批量寫優(yōu)化
在項目中使用批量數(shù)據(jù)插入,經(jīng)常會用到 mybatis的 foreach,如下:
<insert id="batchInsert" parameterType="java.util.List">
insert into USER (id, name) values
<foreach collection="list" item="model" index="index" separator=",">
(#{model.id}, #{model.name})
</foreach>
</insert>就是將
INSERT INTO `table1` (`field1`, `field2`) VALUES ("data1", "data2");
INSERT INTO `table1` (`field1`, `field2`) VALUES ("data1", "data2");
INSERT INTO `table1` (`field1`, `field2`) VALUES ("data1", "data2");
INSERT INTO `table1` (`field1`, `field2`) VALUES ("data1", "data2");
INSERT INTO `table1` (`field1`, `field2`) VALUES ("data1", "data2");轉(zhuǎn)換成
INSERT INTO `table1` (`field1`, `field2`)
VALUES ("data1", "data2"),
("data1", "data2"),
("data1", "data2"),
("data1", "data2"),
("data1", "data2");從理論上將,復(fù)用conn,將多次io,轉(zhuǎn)換成一次io,應(yīng)該是提升效率的。但是實際上當數(shù)據(jù)量比較大的時候,用foreach效率非常低,速度非常慢
當表的列數(shù)較多(20+),以及一次性插入的行數(shù)較多(5000+)時,整個插入的耗時十分漫長,達到了14分鐘,這是不能忍的
那為什么使用使用foreach效率如此之低呢??
Mybatis默認執(zhí)行器類型為Simple,默認會為每一個sql產(chǎn)生一個PrepareStatement,而且對于foreach無法使用緩存。如果字段和行數(shù)非常多,那么sql必然也會很長,占位符也會非常多,除此之外還要建立占位符和參數(shù)之間的映射,那么解析時間必然會長。因此如果values行數(shù)越多,那么解析時間必然很長。執(zhí)行效率低。

如果非要使用 foreach 的方式來進行批量插入的話,可以考慮減少一條 insert 語句中 values 的個數(shù),最好能達到上面曲線的最底部的值,使速度最快。一般按經(jīng)驗來說,一次性插20~50行數(shù)量是比較合適的,時間消耗也能接受。
那么如果要用批量插入,改如何優(yōu)化呢?
SqlSession session = sqlSessionFactory.openSession(ExecutorType.BATCH);
try {
SimpleTableMapper mapper = session.getMapper(SimpleTableMapper.class);
List<SimpleTableRecord> records = getRecordsToInsert(); // not shown
BatchInsert<SimpleTableRecord> batchInsert = insert(records)
.into(simpleTable)
.map(id).toProperty("id")
.map(firstName).toProperty("firstName")
.map(lastName).toProperty("lastName")
.map(birthDate).toProperty("birthDate")
.map(employed).toProperty("employed")
.map(occupation).toProperty("occupation")
.build()
.render(RenderingStrategy.MYBATIS3);
batchInsert.insertStatements().stream().forEach(mapper::insert);
session.commit();
} finally {
session.close();
}基本思想是將 MyBatis session 的 executor type 設(shè)為 Batch ,然后通過遍歷多次執(zhí)行插入語句
就類似于JDBC的下面語句一樣。
Connection connection = DriverManager.getConnection("jdbc:mysql://127.0.0.1:3306/mydb?useUnicode=true&characterEncoding=UTF-8&useServerPrepStmts=false&rewriteBatchedStatements=true","root","root");
connection.setAutoCommit(false);
PreparedStatement ps = connection.prepareStatement(
"insert into tb_user (name) values(?)");
for (int i = 0; i < stuNum; i++) {
ps.setString(1,name);
ps.addBatch();
}
ps.executeBatch();
connection.commit();
connection.close();附錄:Mybatis批量處理優(yōu)化
Mybatis內(nèi)置的ExecutorType有3種,默認的是simple單句模式,該模式下它為每個語句的執(zhí)行創(chuàng)建一個新的預(yù)處理語句,單句提交sql;batch模式重復(fù)使用已經(jīng)預(yù)處理的語句,并且批量執(zhí)行所有語句,大批量模式下性能更優(yōu)。
請注意batch模式在Insert操作時事務(wù)沒有提交之前,是沒有辦法獲取到自增的id,所以請根據(jù)業(yè)務(wù)情況使用。
使用simple模式提交10000條數(shù)據(jù),時間為19s,batch模式為6s ,大致情況如此,優(yōu)化的具體還要看提交的語句情況。
如果需要使用 foreach來優(yōu)化數(shù)據(jù)插入的話,需要將每次插入的記錄控制在 10-100 左右是比較快的,建議每次100來分割數(shù)據(jù),也就是分而治之思想。
普通插入
默認的插入方式是遍歷insert語句,單條執(zhí)行,效率肯定低下,如果成堆插入,更是性能有問題。
INSERT INTO `table1` (`field1`, `field2`) VALUES ("data1", "data2");
INSERT INTO `table1` (`field1`, `field2`) VALUES ("data1", "data2");
INSERT INTO `table1` (`field1`, `field2`) VALUES ("data1", "data2");
INSERT INTO `table1` (`field1`, `field2`) VALUES ("data1", "data2");
INSERT INTO `table1` (`field1`, `field2`) VALUES ("data1", "data2");foreach 優(yōu)化插入
如果要優(yōu)化插入速度時,可以將許多小型操作組合到一個大型操作中。理想情況下,這樣可以在單個連接中一次性發(fā)送許多新行的數(shù)據(jù),并將所有索引更新和一致性檢查延遲到最后才進行。
<insert id="batchInsert" parameterType="java.util.List">
insert into table1 (field1, field2) values
<foreach collection="list" item="t" index="index" separator=",">
(#{t.field1}, #{t.field2})
</foreach>
</insert>翻譯成sql語句也就是
INSERT INTO `table1` (`field1`, `field2`)
VALUES ("data1", "data2"),
("data1", "data2"),
("data1", "data2"),
("data1", "data2"),
("data1", "data2");到此這篇關(guān)于Mybatis 大數(shù)據(jù)量批量寫優(yōu)化的文章就介紹到這了,更多相關(guān)Mybatis 批量寫優(yōu)化內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
postman中參數(shù)和x-www-form-urlencoded傳值的區(qū)別及說明
在Postman中,參數(shù)傳遞有多種方式,其中params和x-www-form-urlencoded最為常用,Params主要用于URL中傳遞查詢參數(shù),適合GET請求和非敏感數(shù)據(jù),其特點是將參數(shù)作為查詢字符串附加在URL末尾,適用于過濾和排序等操作2024-09-09
idea2019.2安裝MybatisCodeHelper插件的超詳細教程
這篇文章主要介紹了idea2019.2安裝MybatisCodeHelper插件的教程,本文給大家介紹的非常詳細,對大家的學(xué)習(xí)或工作具有一定的參考借鑒價值,需要的朋友可以參考下2020-09-09
詳解MyBatis Generator自動創(chuàng)建代碼(dao,mapping,poji)
這篇文章主要介紹了詳解MyBatis Generator自動創(chuàng)建代碼(dao,mapping,poji)的相關(guān)資料,非常不錯,具有參考借鑒價值,需要的朋友可以參考下2016-10-10

