作者 | 蔡柱梁
審校 | 重樓
前言
在很多公司,經(jīng)常聽到“不要用 mybatis-plus 的批量插入,它其實也是遍歷插入,性能很差的”。真的是這樣嗎?我們不應(yīng)該人云亦云,應(yīng)該自己去探究下。
我們先針對這個觀點分析下,總結(jié)出來他們的看法大概率是下面的其中一種:
- 遍歷插入,反復(fù)創(chuàng)建。這是一個比較重的操作,所以性能很差。
這里不用看源碼也能知道,因為這個和mybatis-plus沒關(guān)系,而且我們現(xiàn)在使用了SpringBoot,一般也用它的JDBC啟動依賴。連接和連接池不是本章節(jié)的重點,就不展開講了,總的來說這觀點是不正確的。 - 一條 insert 就一次網(wǎng)絡(luò)IO,數(shù)量多了,這是個很可觀且沒必要的開銷,所以性能差。
走進源碼
對這第二個觀點,筆者結(jié)合源碼給出自己的觀點。給出筆者的一些相關(guān)配置(我使用mybatis-plus的版本是3.5.3.1)。
pom.xml如下:
...
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jdbc</artifactId>
</dependency>
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-boot-starter</artifactId>
<version>3.5.3.1</version>
</dependency>
...
application.yml如下:
Spring:
# 使用默認的連接池庫
datasource:
url: "*****"
username: "****"
password: "****"
筆者的Service如下圖:
1 進入 saveBatch 看下
com.baomidou.mybatisplus.extension.service.IService#saveBatch(java.util.Collection)
發(fā)現(xiàn)里面會給我們這個批量操作開啟了事務(wù)(如果是期望插入一條就成功一條的,這批量方法就不適用了)并且是有限制提交數(shù)量的,默認1000。
2 往里ServiceImpl#saveBatch走
com.baomidou.mybatisplus.extension.service.impl.ServiceImpl#saveBatch
看到了mybatis-plus 的批量插入是一條條插入的,但是這個一次次的遍歷是真的發(fā)送給MySQL了嗎?這里留一個疑問。我們只要記得這里有一個鉤子,后面會回調(diào)回來執(zhí)行
3 SqlHelper#executeBatch(Class<?>, Log, Collection, int, BiConsumer<SqlSession,E>)
com.baomidou.mybatisplus.extension.toolkit.SqlHelper#executeBatch(java.lang.Class<?>, org.apache.ibatis.logging.Log, java.util.Collection, int, java.util.function.BiConsumer<org.apache.ibatis.session.SqlSession,E>)
sqlSession 是從哪里來的呢?我們?nèi)タ聪陆貓D里面的executeBatch。
4 SqlHelper#executeBatch(Class<?> entityClass, Log log, Consumer consumer)
com.baomidou.mybatisplus.extension.toolkit.SqlHelper#executeBatch(java.lang.Class<?>, org.apache.ibatis.logging.Log, java.util.function.Consumer<org.apache.ibatis.session.SqlSession>)
結(jié)合前面的代碼就知道了,我這里是到了1000(默認配置1000,并且我批量保存的list超過了1000),就會開啟會話,將內(nèi)存的sql全部刷到MySQL,然后回去繼續(xù)遍歷。
總結(jié)
到這里大家應(yīng)該都清楚的知道了 mybatis-plus 的批量插入雖然是遍歷插入,但是不是一個insert就一次IO,而是打包了一次發(fā)送一批的,所以性能不會有什么太大問題。不過,筆者這里不是鼓吹大家都用這個批量插入就好了,實際工作中會有更多要求,有時這個簡單的批量插入是沒法滿足的。因此,筆者只是提倡可以根據(jù)自己工作實際情況決定,但是性能方面就不用太過擔心,mybatis-plus 也有考慮的。
擴展
如果使用mybatis-plus 3.4+ 版本,并且連接的是 MySQL 8.0 或更高版本的數(shù)據(jù)庫,那么 mybatis-plus將會自動利用MySQL 8.0 的原生批量插入功能來執(zhí)行批量插入操作。
具體實現(xiàn)的關(guān)鍵是在mybatis-plus的底層使用了mybatis-plus的批量新增方法時,mybatis-plus會將待插入的對象列表傳遞給底層的而
需要注意的是,要確保以下條件滿足才能利用
- 使用
- 使用兼容
- 使用mybatis-plus 3.4+ 版本
作者介紹
蔡柱梁,51CTO社區(qū)編輯,從事Java后端開發(fā)8年,做過傳統(tǒng)項目廣電BOSS系統(tǒng),后投身互聯(lián)網(wǎng)電商,負責過訂單,TMS,中間件等。