點選上方“芋道原始碼”,選擇“置頂公眾號”
技術文章第一時間送達!
原始碼精品專欄
來源:http://t.cn/E70PpTf
資料庫使用的是sqlserver,JDK版本1.8,執行在SpringBoot環境下
對比3種可用的方式
1、反覆執行單條插入陳述句
2、xml拼接sql
3、批處理執行
先說結論:少量插入請使用反覆插入單條資料,方便。數量較多請使用批處理方式。(可以考慮以有需求的插入資料量20條左右為界吧,在我的測試和資料庫環境下耗時都是百毫秒級的,方便最重要)。無論何時都不用xml拼接sql的方式。
程式碼
拼接SQL的xml
newId()是sqlserver生成UUID的函式,與本文內容無關
<insert id="insertByBatch" parameterType="java.util.List">
INSERT INTO tb_item VALUES
<foreach collection="list" item="item" index="index" separator=",">
(newId(),#{item.uniqueCode},#{item.projectId},#{item.name},#{item.type},#{item.packageUnique},
#{item.isPackage},#{item.factoryId},#{item.projectName},#{item.spec},#{item.length},#{item.weight},
#{item.material},#{item.setupPosition},#{item.areaPosition},#{item.bottomHeight},#{item.topHeight},
#{item.serialNumber},#{item.createTime}foreach>
insert>
Mapper介面
Mapper
public interface ItemMapper extends Mapper<Item> {
int insertByBatch(List- itemList)
;
}
Service類
@Service
public class ItemService {
@Autowired
private ItemMapper itemMapper;
@Autowired
private SqlSessionFactory sqlSessionFactory;
//批處理
@Transactional
public void add(List- itemList)
{
SqlSession session = sqlSessionFactory.openSession(ExecutorType.BATCH,false);
ItemMapper mapper = session.getMapper(ItemMapper.class);
for (int i = 0; i mapper.insertSelective(itemList.get(i));
if(i%1000==999){//每1000條提交一次防止記憶體上限溢位
session.commit();
session.clearCache();
}
}
session.commit();
session.clearCache();
}
//拼接sql
@Transactional
public void add1(List- itemList)
{
itemList.insertByBatch(itemMapper::insertSelective);
}
//迴圈插入
@Transactional
public void add2(List- itemList)
{
itemList.forEach(itemMapper::insertSelective);
}
}
測試類
@RunWith(SpringRunner.class)
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT, classes = ApplicationBoot.class)
public class ItemServiceTest {
@Autowired
ItemService itemService;
private List- itemList = new ArrayList<>();
//生成測試List
@Before
public void createList(){
String json ="{\n" +
" \"areaPosition\": \"TEST\",\n" +
" \"bottomHeight\": 5,\n" +
" \"factoryId\": \"0\",\n" +
" \"length\": 233.233,\n" +
" \"material\": \"Q345B\",\n" +
" \"name\": \"TEST\",\n" +
" \"package\": false,\n" +
" \"packageUnique\": \"45f8a0ba0bf048839df85f32ebe5bb81\",\n" +
" \"projectId\": \"094b5eb5e0384bb1aaa822880a428b6d\",\n" +
" \"projectName\": \"專案_TEST1\",\n" +
" \"serialNumber\": \"1/2\",\n" +
" \"setupPosition\": \"1B柱\",\n" +
" \"spec\": \"200X200X200\",\n" +
" \"topHeight\": 10,\n" +
" \"type\": \"Steel\",\n" +
" \"uniqueCode\": \"12344312\",\n" +
" \"weight\": 100\n" +
" }";
Item test1 = JSON.parseObject(json,Item.class);
test1.setCreateTime(new Date());
for (int i = 0; i 1000; i++) {//測試會修改此數量
itemList.add(test1);
}
}
//批處理
@Test
@Transactional
public void tesInsert() {
itemService.add(itemList);
}
//拼接字串
@Test
@Transactional
public void testInsert1(){
itemService.add1(itemList);
}
//迴圈插入
@Test
@Transactional
public void testInsert2(){
itemService.add2(itemList);
}
}
測試結果:
10條 25條資料插入經多次測試,波動性較大,但基本都在百毫秒級別
方式 | 50條 | 100條 | 500條 | 1000條 |
---|---|---|---|---|
批處理 | 159ms | 208ms | 305ms | 432ms |
xml拼接sql | 208ms | 232ms | 報錯 | 報錯 |
反覆單條插入 | 1013ms | 2266ms | 8141ms | 18861ms |
其中 拼接sql方式在插入500條和1000條時報錯(似乎是因為sql陳述句過長,此條跟資料庫型別有關,未做其他資料庫的測試):
com.microsoft.sqlserver.jdbc.SQLServerException: 傳入的表格格式資料流(TDS)遠端過程呼叫(RPC)協議流不正確。此 RPC 請求中提供了過多的引數。最多應為 2100
可以發現
1、迴圈插入的時間複雜度是 O(n),並且常數C很大
2、拼接SQL插入的時間複雜度(應該)是 O(logn),但是成功完成次數不多,不確定
3、批處理的效率的時間複雜度是 O(logn),並且常數C也比較小
結論
迴圈插入單條資料雖然效率極低,但是程式碼量極少,在使用tk.Mapper的外掛情況下,僅需程式碼,:
@Transactional
public void add1(List- itemList) {
itemList.forEach(itemMapper::insertSelective);
}
因此,在需求插入資料數量不多的情況下肯定用它了。
xml拼接sql是最不推薦的方式,使用時有大段的xml和sql陳述句要寫,很容易出錯,工作效率很低。更關鍵點是,雖然效率尚可,但是真正需要效率的時候你掛了,要你何用?
批處理執行是有大資料量插入時推薦的做法,使用起來也比較方便。
如果你對 Dubbo / Netty 等等原始碼與原理感興趣,歡迎加入我的知識星球一起交流。長按下方二維碼噢:
目前在知識星球更新了《Dubbo 原始碼解析》目錄如下:
01. 除錯環境搭建
02. 專案結構一覽
03. 配置 Configuration
04. 核心流程一覽
05. 拓展機制 SPI
06. 執行緒池
07. 服務暴露 Export
08. 服務取用 Refer
09. 註冊中心 Registry
10. 動態編譯 Compile
11. 動態代理 Proxy
12. 服務呼叫 Invoke
13. 呼叫特性
14. 過濾器 Filter
15. NIO 伺服器
16. P2P 伺服器
17. HTTP 伺服器
18. 序列化 Serialization
19. 叢集容錯 Cluster
20. 優雅停機
21. 日誌適配
22. 狀態檢查
23. 監控中心 Monitor
24. 管理中心 Admin
25. 運維命令 QOS
26. 鏈路追蹤 Tracing
… 一共 69+ 篇
目前在知識星球更新了《Netty 原始碼解析》目錄如下:
01. 除錯環境搭建
02. NIO 基礎
03. Netty 簡介
04. 啟動 Bootstrap
05. 事件輪詢 EventLoop
06. 通道管道 ChannelPipeline
07. 通道 Channel
08. 位元組緩衝區 ByteBuf
09. 通道處理器 ChannelHandler
10. 編解碼 Codec
11. 工具類 Util
… 一共 61+ 篇
目前在知識星球更新了《資料庫物體設計》目錄如下:
01. 商品模組
02. 交易模組
03. 營銷模組
04. 公用模組
… 一共 17+ 篇
目前在知識星球更新了《Spring 原始碼解析》目錄如下:
01. 除錯環境搭建
02. IoC Resource 定位
03. IoC BeanDefinition 載入
04. IoC BeanDefinition 註冊
05. IoC Bean 獲取
06. IoC Bean 生命週期
… 一共 35+ 篇
原始碼不易↓↓↓↓↓
點贊支援老艿艿↓↓