欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

mybatis和mybatisplus批量插入問題示例詳解

 更新時間:2023年04月12日 11:51:53   作者:又?欠  
最近在處理一個功能的時候,需要批量插入數據,這篇文章主要給大家介紹了關于mybatis和mybatisplus批量插入問題的相關資料,文中通過實例代碼介紹非常詳細,需要的朋友可以參考下

1. 思路分析:

批量插入是我們日常開放經常會使用到的場景,一般情況下我們也會有兩種方案進行實施,如下所示。

方案一 就是用 for 循環(huán)循環(huán)插入:

優(yōu)點:JDBC 中的 PreparedStatement 有預編譯功能,預編譯之后會緩存起來,后面的 SQL 執(zhí)行會比較快并且JDBC 可以開啟批處理,這個批處理執(zhí)行非常給力。

缺點:很多時候我們的 SQL 服務器和應用服務器可能并不是同一臺,所以必須要考慮網絡 IO,如果網絡 IO 比較費時間的話,那么可能會拖慢
SQL 執(zhí)行的速度。

再來說第二種方案,就是生成一條 SQL 插入:

優(yōu)勢:這種方案的優(yōu)勢在于只有一次網絡 IO,即使分片處理也只是數次網絡 IO,所以這種方案不會在網絡 IO 上花費太多時間。

缺點一是 SQL 太長了,甚至可能需要分片后批量處理;

缺點二是無法充分發(fā)揮 PreparedStatement 預編譯的優(yōu)勢,SQL 要重新解析且無法復用;三是最終生成的 SQL
太長了,數據庫管理器解析這么長的 SQL 也需要時間。

2. rewriteBatchedStatements=true

在jdbc連接后面加上 rewriteBatchedStatements=true ,加上后才是真正的批量插入。

jdbc:mysql://127.0.0.1:3306/test?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=true&serverTimezone=GMT%2B8&rewriteBatchedStatements=true

3.使用mybatis批量插入:

方案一:使用foreach進行插入(生成一條 SQL 插入)

mapper文件

   <insert id="save" parameterType="java.util.List">
        INSERT INTO test
        (
        id,
        a,
        b,
        c
        )
        VALUES
        <foreach collection="list" item="item" index="index" separator=",">
            (
            #{item.id},
            #{item.a},
            #{item.b},
            #{item.c}
            )
        </foreach>
    </insert>

調用方法

 @Override
    public void add() {
        //時間 一
        long l = System.currentTimeMillis();
        List<TestEntity> list=new ArrayList<>();
        for (int i=0;i<1000;i++){
            TestEntity testEntity=new TestEntity();
            testEntity.setC(i);
            list.add(testEntity);
        }
       testMapper.save(list);
        //時間 二
        long l1 = System.currentTimeMillis();
        System.out.println("耗時"+(l1-l));
    }

插入了1000條數據,耗時535毫秒。

插入了50000條數據,直接報錯。

報錯原因是因為我們一條SQL進行插入導致SQL太長

解決辦法:

1.修改MySQL配置

2.對新增數據進行分片

方案二:一條條插入

mapper

   <insert id="addUserOneByOne" parameterType="com.ruoyi.system.domain.TestEntity">
    insert into test (id,a,b,c) values (#{id},#{a},#,#{c})
    </insert>

測試代碼

@Service
public class TestServiceimpl extends ServiceImpl<TestMapper, TestEntity> implements TestService {

    @Autowired
  private   TestMapper testMapper;

    @Autowired
  private SqlSessionFactory sqlSessionFactory;
    
    public void addUserOneByOne(List<TestEntity> users) {
        SqlSession session = sqlSessionFactory.openSession(ExecutorType.BATCH);
        TestMapper um = session.getMapper(TestMapper.class);
        long startTime = System.currentTimeMillis();
        for (TestEntity user : users) {
            um.addUserOneByOne(user);
        }
        session.commit();
        long endTime = System.currentTimeMillis();
        System.out.println("耗時"+(endTime - startTime));
    }
}

插入了1000條數據,耗時959毫秒。

插入50000條數據,耗時11214毫秒。

對比分析:

如果我們批量插入少部分數據,可以使用方式一,一條SQL進行插入。這樣是比較快的。

如果我們插入數據達到,1w條,10來萬條,這時建議用方式二進行插入是比較快的。

4. 使用mybatisplus批量插入

使用saveBatch()方法進行批量插入

@Service
public class TestServiceimpl extends ServiceImpl<TestMapper, TestEntity> implements TestService {
    
    @Autowired
  private   TestMapper testMapper;

    @Autowired
  private SqlSessionFactory sqlSessionFactory;

    @Override
    public void add() {
        //時間 一
        long l = System.currentTimeMillis();
        List<TestEntity> list=new ArrayList<>();
        for (int i=0;i<50000;i++){
            TestEntity testEntity=new TestEntity();
            testEntity.setC(i);
            list.add(testEntity);
        }
        saveBatch(list);
        //時間 二
        long l1 = System.currentTimeMillis();
        System.out.println("耗時"+(l1-l));
    }

插入50000條數據,耗時19516毫秒

源碼分析

   public boolean saveBatch(Collection<T> entityList, int batchSize) {
        String sqlStatement = this.getSqlStatement(SqlMethod.INSERT_ONE);
        return this.executeBatch(entityList, batchSize, (sqlSession, entity) -> {
            sqlSession.insert(sqlStatement, entity);
        });
    }

這里注意 return 中的第三個參數,是一個 lambda 表達式,這也是 MP 中批量插入的核心邏輯,可以看到,MP 先對數據進行分片(默認分片大小是 1000),分片完成之后,也是一條一條的插入。

 public static <E> boolean executeBatch(Class<?> entityClass, Log log, Collection<E> list, int batchSize, BiConsumer<SqlSession, E> consumer) {
        Assert.isFalse(batchSize < 1, "batchSize must not be less than one", new Object[0]);
        return !CollectionUtils.isEmpty(list) && executeBatch(entityClass, log, (sqlSession) -> {
            int size = list.size();
            int i = 1;

            for(Iterator var6 = list.iterator(); var6.hasNext(); ++i) {
                E element = var6.next();
                consumer.accept(sqlSession, element);
                if (i % batchSize == 0 || i == size) {
                    sqlSession.flushStatements();
                }
            }

        });
    }

繼續(xù)查看 executeBatch 方法,就會發(fā)現這里的 sqlSession 其實也是一個批處理的 sqlSession,并非普通的 sqlSession。和我們mybatis使用的方法二一致。

5業(yè)務場景一對多怎么處理:

比如,如下這種一對多場景。

新增的時候保存都好理解,形成一個數組一起保存。

而修改的時候就有點難處理了,比如我修改了第二條,刪除了第三條,這時統一保存應該怎么處理?

使用 ON DUPLICATE KEY UPDATE (發(fā)生主鍵沖突就更新,沒有發(fā)生主鍵沖突就新增)

有時候由于業(yè)務需求,可能需要先去根據某一字段值查詢數據庫中是否有記錄,有則更新,沒有則插入。這個時候就可以用到ON DUPLICATE key update這個sql語句了

mapper如下所示

   <insert id="save" parameterType="java.util.List">
        INSERT INTO test
        (
        id,
        a,
        b,
        c
        )
        VALUES
        <foreach collection="list" item="item" index="index" separator=",">
            (
            #{item.id},
            #{item.a},
            #{item.b},
            #{item.c}
            )
        </foreach>
        ON DUPLICATE KEY UPDATE
        id=id,
        a = VALUES(a) ,
        b = VALUES(b),
        c = VALUES(c)
    </insert>

或者在使用mybatisplus時,使用saveOrUpdate()方法進行一條數據的新增或更新。 saveOrUpdateBatch()方法進行批量數據的新增或更新。

總結

到此這篇關于mybatis和mybatisplus批量插入問題的文章就介紹到這了,更多相關mybatis mybatisplus批量插入問題內容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關文章希望大家以后多多支持腳本之家!

相關文章

  • IDEA中Javaweb項目圖片加載不出來解決方案

    IDEA中Javaweb項目圖片加載不出來解決方案

    在IDEA中能夠正常的預覽到圖片,但是在生成項目的war包時,項目的目錄結構卻會發(fā)生變化,所以無法訪問圖片,本文主要介紹了IDEA中Javaweb項目圖片加載不出來解決方案,感興趣的可以了解一下
    2023-10-10
  • Java連接redis及基本操作示例

    Java連接redis及基本操作示例

    這篇文章主要介紹了Java連接redis及基本操作,結合實例形式較為詳細的分析了java針對redis數據庫的基本連接、配置及操作相關實現技巧,需要的朋友可以參考下
    2019-04-04
  • Spring Boot Admin Server管理客戶端過程詳解

    Spring Boot Admin Server管理客戶端過程詳解

    這篇文章主要介紹了Spring Boot Admin Server管理客戶端過程詳解,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友可以參考下
    2020-03-03
  • java比較器Comparable接口與Comaprator接口的深入分析

    java比較器Comparable接口與Comaprator接口的深入分析

    本篇文章是對java比較器Comparable接口與Comaprator接口進行了詳細的分析介紹,需要的朋友參考下
    2013-06-06
  • 基于Java ActiveMQ的實例講解

    基于Java ActiveMQ的實例講解

    下面小編就為大家?guī)硪黄贘ava ActiveMQ的實例講解。小編覺得挺不錯的,現在就分享給大家,也給大家做個參考。一起跟隨小編過來看看吧
    2017-09-09
  • java實現單鏈表中的增刪改

    java實現單鏈表中的增刪改

    這篇文章主要為大家詳細介紹了java實現單鏈表中的增刪改,文中示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2022-05-05
  • Java結構型設計模式之組合模式Composite Pattern詳解

    Java結構型設計模式之組合模式Composite Pattern詳解

    組合模式,又叫部分整體模式,它創(chuàng)建了對象組的數據結構組合模式使得用戶對單個對象和組合對象的訪問具有一致性。本文將通過示例為大家詳細介紹一下組合模式,需要的可以參考一下
    2022-11-11
  • Java?C++題解eetcode940不同的子序列?II

    Java?C++題解eetcode940不同的子序列?II

    這篇文章主要為大家介紹了Java?C++題解eetcode940不同的子序列?II實現示例,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪
    2022-10-10
  • springboot中設置定時任務的三種方法小結

    springboot中設置定時任務的三種方法小結

    在我們開發(fā)項目過程中,經常需要定時任務來幫助我們來做一些內容,本文介紹了springboot中設置定時任務的三種方法,主要包括@Scheduled注解,Quartz框架和xxl-job框架的實現,感興趣的可以了解一下
    2023-12-12
  • Java中的Vector和Stack底層源碼分析

    Java中的Vector和Stack底層源碼分析

    這篇文章主要介紹了Java中的Vector和Stack底層源碼分析,Stack繼承了Vector,Vector底層還是一個List,也就是基于數組來實現的,所以ArrayList有的優(yōu)點,比如獲取元素的速度快,隨機讀,它都有,需要的朋友可以參考下
    2023-12-12

最新評論