前言
今天在網上看到一篇文章(后文中的文章指的就是它)
https://www.jianshu.com/p/cce617be9f9e
發現了一種有關於mybatis批量插入的新方法,而且看了文章發現我原來的方法好像有點問題,但是由於文章中使用的環境是sqlserver而我經常使用的是mysql所以還是需要親自來試試。
環境說明
項目使用springboot mybatis
數據庫mysql5.7
使用本地mysql所以網絡可以忽略不計
插入對象完全相同,只有id自增
表結構如下:
CREATE TABLE order_test_tab
(
id
int(11) NOT NULL AUTO_INCREMENT COMMENT 'id',
order_id
varchar(20) NOT NULL COMMENT '訂單號',
order_name
varchar(100) NOT NULL COMMENT '訂單名稱',
order_status
int(1) NOT NULL COMMENT '訂單狀態',
order_content
varchar(255) NOT NULL COMMENT '訂單說明',
add_time
datetime NOT NULL COMMENT '訂單時間',
PRIMARY KEY (id
)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='測試訂單表';
方法說明
我使用了和文章中提到的一樣,三種方法進行測試
方法一:
使用for循環調用單條插入


方法二:
在sql中使用foreach進行批量insert

方法三:
使用mybatis的批量插入

結果說明
插入條數 | 100 | 500 | 1000 | 5000 | 100000 |
---|---|---|---|---|---|
使用for循環插入 | 139ms | 545ms | 839ms | 2629ms | 31157ms |
使用sql foreach插入 | 55ms | 119ms | 123ms | 329ms | 報錯 |
使用批量執行插入 | 48ms | 111ms | 239ms | 1081ms | 19235ms |
其中報錯是因為sql長度過長超過了max_allowed_packet導致的,報錯信息如下:
Error updating database. Cause: com.mysql.cj.jdbc.exceptions.PacketTooBigException: Packet for query is too large (22,700,108 > 4,194,304). You can change this value on the server by setting the 'max_allowed_packet' variable.
從結果我們顯然可以看出,使用第二種方式(使用sql foreach插入)效率最高,明顯與文章中差距很大,所以mysql和sqlserver還是有很大區別的,估計mysql針對批量插入的語句有過優化
測試說明
1.測試具體插入之前,首先執行刪除表中所有數據操作,一個是保證環境完全一致,一個是為了減少第一次連接數據庫所帶來的性能消耗。
2.執行時間的計算就是在執行sql的前后,創建對象的時間不計算在這之內
3.在使用本地mysql測試完成之后,使用外網服務器的mysql進行測試,測試結果基本一致,時間都略有延長
4.測試代碼在:https://github.com/LinkinStars/springBootTemplate/tree/test-batch-insert
其中包含order字樣的為測試相關代碼,別的是無關代碼,入口在test包下的OrderTest.java
結論
批量插入時還是使用sql foreach插入來的效率最高,因為它是整一條sql在執行所以當插入條數很多的時候會出現異常,所以使用這種方式時一定要主動限制插入的最大條數,不然容易出現異常,因為max_allowed_packet即使再大也會有不夠用的時候。
同時我們也應該竟可能去避免使用for循環插入數據,因為性能真的很差。