最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

mybatis中大批量數(shù)據(jù)插入解析

 更新時間:2024年01月23日 10:48:45   作者:小星星*  
這篇文章主要介紹了mybatis中大批量數(shù)據(jù)插入解析,使用Mybatis框架批量插入的3種方法,分別是多次調(diào)用insert方法、foreach標(biāo)簽、batch模式,本文來詳細說明一下,需要的朋友可以參考下

mybatis批量數(shù)據(jù)插入

本文測試三種方式,插入大量數(shù)據(jù)(10萬以上)到mysql數(shù)據(jù)庫中,有以下幾種方式

  • 普通方式
  • foreach批量插入
  • ExecutorType.BATCH插入

1 user實體類

@Setter
@Getter
public class User {
    private Long id;
    private String phone;
    private String name;
}

2 IUserService

public interface IUserService {
    void insertUsers();
    void insertUser();
    void batchInsert();
    void insertUsersBatch();
}

3 userService類

package com.bear.dbinserttest;
import org.apache.ibatis.session.ExecutorType;
import org.apache.ibatis.session.SqlSession;
import org.mybatis.spring.SqlSessionTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import javax.annotation.Resource;
import java.util.ArrayList;
import java.util.List;
/**
 * @description:
 * @author: zhoushaoxiong
 * @date: 2023/6/8 11:08
 */
@Service
public class UserService implements IUserService {
    private static int count = 1000000;
    @Resource
    private IUserDao userDao;
    @Autowired
    private SqlSessionTemplate sqlSessionTemplate;
    @Override
    public void insertUser(){
        List<User> userList = new ArrayList<>();
        Long start = System.currentTimeMillis();
        for (int i=0; i<count; i++){
            User user = new User();
            user.setName("name"+i);
            user.setPhone("phonephone"+i);
            userList.add(user);
            userDao.insertUser(user);
        }
        Long usedTime = (System.currentTimeMillis()-start);
        System.out.println("插入"+count+"條數(shù)據(jù)耗時::" + usedTime);
    }
    @Override
    //foreach插入
    public void insertUsers() {
        List<User> userList = new ArrayList<>();
        int batch = 20000;
        Long start = System.currentTimeMillis();
        for (int i=0; i<count; i++){
            User user = new User();
            user.setName("name"+i);
            user.setPhone("phonephone"+i);
            userList.add(user);
            if(userList.size()>=batch){  //mysql的sql語句有4M的大小限制,不能全部放在一個foreach
                userDao.insertUsers(userList);
                userList.clear();
            }
        }
        if(userList.size()>0){
            userDao.insertUsers(userList);
        }
        Long usedTime = (System.currentTimeMillis()-start);
        System.out.println("插入"+count+"條數(shù)據(jù)耗時::" + usedTime);
    }
    @Override
    //ExecutorType.BATCH插入
    public void insertUsersBatch(){
        //手動創(chuàng)建userDao
        SqlSession sqlSession = sqlSessionTemplate.getSqlSessionFactory().openSession(ExecutorType.BATCH, false);
        IUserDao userDao2 = sqlSession.getMapper(IUserDao.class);
        Long start = System.currentTimeMillis();
        int batch = 1000;
        for (int i=0; i<count; i++){
            User user = new User();
            user.setName("name"+i);
            user.setPhone("phonephone"+i);
            userDao2.insertUser(user);
            if(i!=0 && i%batch==0){  //1000條提交一次
                sqlSession.commit();
            }
        }
        sqlSession.commit();
        Long usedTime = (System.currentTimeMillis()-start);
        System.out.println("插入"+count+"條數(shù)據(jù)耗時::" + usedTime);
    }
}

4 IUserDao

package com.bear.dbinserttest;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Param;
import org.mybatis.spring.annotation.MapperScan;
import java.util.List;
/**
 * @description:
 * @author: zhoushaoxiong
 * @date: 2023/6/8 11:15
 */
public interface IUserDao {
    void insertUsers(List<User> userList);
    void insertUser(User user);
    void batchInsert(@Param("list") List<User> list);
    void insertUsersBatch(List<User> users);
}

5 UserMapper

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd" >
<mapper namespace="com.bear.dbinserttest.IUserDao" >
    <insert id="insertUser" parameterType="com.bear.dbinserttest.User">
        insert into user(name, phone) values (#{name}, #{phone})
    </insert>
    <-- 普通插入 --/>
    <insert id="insertUsers" parameterType="com.bear.dbinserttest.User">
        insert into user(name, phone) values
        <foreach collection="userList" item="user" separator=",">
            (#{user.name}, #{user.phone})
        </foreach>
    </insert>
    <-- foreach插入 --/>
    <insert id="batchInsert" parameterType="com.bear.dbinserttest.User">
        <foreach collection="list" item="item" separator=";" >
            insert into user
            <trim prefix="(" suffix=")" suffixOverrides=",">
                <if test="item.id != null">
                    id,
                </if>
                <if test="item.name != null">
                    `name`,
                </if>
                <if test="item.phone != null">
                    `phone`,
                </if>
            </trim>
            <trim prefix="values (" suffix=")" suffixOverrides=",">
                <if test="item.id != null">
                    #{item.id,jdbcType=INTEGER},
                </if>
                <if test="item.name != null">
                    #{item.name,jdbcType=VARCHAR},
                </if>
                <if test="item.phone != null">
                    #{item.phone,jdbcType=VARCHAR},
                </if>
            </trim>
        </foreach>
    </insert>
    <-- ExecutorType.BATCH插入 --/>
    <insert id="insertUsersBatch" parameterType="com.bear.dbinserttest.User">
        insert into user(name, phone) values (#{name}, #{phone})
    </insert>
</mapper>

6 application.yml 配置文件

url必須設(shè)置rewriteBatchedStatements=true,否則ExecutorType.BATCH插入的方式效率很低

server:
  port: 8080
spring:
  datasource:
    username: root
    password: 123456
    url: jdbc:mysql://localhost:3306/test?useUnicode=true&characterEncoding=utf-8&useSSL=false&serverTimezone=UTC&rewriteBatchedStatements=true
mybatis:
  mapper-locations: classpath:mapper/*.xml

7 DbinserttestApplicationTests 測試類

package com.bear.dbinserttest;
import org.junit.jupiter.api.Test;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
@SpringBootTest
class DbinserttestApplicationTests {
    @Autowired
    IUserService userService;
    @Test
    //測試普通插入
    void contextLoads() {
        userService.insertUser(); //插入100000條數(shù)據(jù)耗時::74895ms
    }
    @Test
    //測試foreach插入
    void contextLoads2() {
        userService.insertUsers(); //插入100000條數(shù)據(jù)耗時::1801ms
    }
    @Test
    //測試ExecutorType.BATCH插入
    void contextLoads3() { 
        userService.insertUsersBatch(); //插入100000條數(shù)據(jù)耗時::1143ms
    }
}

8 小結(jié)

1.普通插入

默認的插入方式是遍歷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");

可以看到每個語句的執(zhí)行創(chuàng)建一個新的預(yù)處理語句,單條提交sql,性能低下.

2.foreach 優(yōu)化插入

如果要優(yōu)化插入速度時,可以將許多小型操作組合到一個大型操作中。理想情況下,這樣可以在單個連接中一次性發(fā)送許多新行的數(shù)據(jù),并將所有索引更新和一致性檢查延遲到最后才進行。

INSERT INTO `table1` (`field1`, `field2`) 
VALUES ("data1", "data2"),
("data1", "data2"),
("data1", "data2"),
("data1", "data2"),
("data1", "data2");

當(dāng)表的列數(shù)較多(20+),以及一次性插入的行數(shù)較多(5000+)時,整個插入的耗時十分漫長,注意耗時在PreparedStatement特別長,包含了很多占位符,對于占位符和參數(shù)的映射尤其耗時

需要注意的點: Mysql 對語句的長度有限制,默認是 4M。

3.ExecutorType.BATCH插入

Mybatis內(nèi)置的ExecutorType有3種,SIMPLE、REUSE、BATCH; 默認的是simple,該模式下它為每個語句的執(zhí)行創(chuàng)建一個新的預(yù)處理語句,單條提交sql;而batch模式重復(fù)使用已經(jīng)預(yù)處理的語句,并且批量執(zhí)行所有更新語句,顯然batch性能將更優(yōu);但batch模式也有自己的問題,比如在Insert操作時,在事務(wù)沒有提交之前,是沒有辦法獲取到自增的id,這在某型情形下是不符合業(yè)務(wù)要求的.

JDBC 在執(zhí)行 SQL 語句時,會將 SQL 語句以及實參通過網(wǎng)絡(luò)請求的方式發(fā)送到數(shù)據(jù)庫,一次執(zhí)行一條 SQL 語句,一方面會減小請求包的有效負載,另一個方面會增加耗費在網(wǎng)絡(luò)通信上的時間。通過批處理的方式,我們就可以在 JDBC 客戶端緩存多條 SQL 語句,然后在 flush 或緩存滿的時候,將多條 SQL 語句打包發(fā)送到數(shù)據(jù)庫執(zhí)行,這樣就可以有效地降低上述兩方面的損耗,從而提高系統(tǒng)性能。

需要注意的點:進行jdbc批處理時需在JDBC的url中加入rewriteBatchedStatements=true

ExecutorType.BATCH原理:把SQL語句發(fā)個數(shù)據(jù)庫,數(shù)據(jù)庫預(yù)編譯好,數(shù)據(jù)庫等待需要運行的參數(shù),接收到參數(shù)后一次運行,ExecutorType.BATCH只打印一次SQL語句,預(yù)編譯一次sql,多次設(shè)置參數(shù)步驟.

經(jīng)過以上三種方式分析,在插入大數(shù)據(jù)量時優(yōu)先選擇第三種方式, ExecutorType.BATCH插入

到此這篇關(guān)于mybatis中大批量數(shù)據(jù)插入解析的文章就介紹到這了,更多相關(guān)mybatis批量數(shù)據(jù)插入內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • interrupt()和線程終止方式_動力節(jié)點Java學(xué)院整理

    interrupt()和線程終止方式_動力節(jié)點Java學(xué)院整理

    線程的thread.interrupt()方法是中斷線程,將會設(shè)置該線程的中斷狀態(tài)位,即設(shè)置為true,中斷的結(jié)果線程是死亡、還是等待新的任務(wù)或是繼續(xù)運行至下一步,就取決于這個程序本身
    2017-05-05
  • Java隊列篇之實現(xiàn)數(shù)組模擬隊列及可復(fù)用環(huán)形隊列詳解

    Java隊列篇之實現(xiàn)數(shù)組模擬隊列及可復(fù)用環(huán)形隊列詳解

    像棧一樣,隊列(queue)也是一種線性表,它的特性是先進先出,插入在一端,刪除在另一端。就像排隊一樣,剛來的人入隊(push)要排在隊尾(rear),每次出隊(pop)的都是隊首(front)的人
    2021-10-10
  • Spring Boot整合MyBatis-Plus實現(xiàn)CRUD操作的示例代碼

    Spring Boot整合MyBatis-Plus實現(xiàn)CRUD操作的示例代碼

    本文主要介紹了Spring Boot整合MyBatis-Plus實現(xiàn)CRUD操作,可以快速實現(xiàn)數(shù)據(jù)庫的增刪改查操作,文中通過示例代碼介紹的非常詳細,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2025-04-04
  • Java底層基于鏈表實現(xiàn)集合和映射--集合Set操作詳解

    Java底層基于鏈表實現(xiàn)集合和映射--集合Set操作詳解

    這篇文章主要介紹了Java底層基于鏈表實現(xiàn)集合和映射集合Set操作,結(jié)合實例形式詳細分析了Java使用鏈表實現(xiàn)集合和映射相關(guān)原理、操作技巧與注意事項,需要的朋友可以參考下
    2020-03-03
  • 教你如何測試Spring Data JPA的Repository

    教你如何測試Spring Data JPA的Repository

    Spring Data JPA 提供了一些便捷的方式來測試這種持久層的代碼,常見的兩種測試類型是集成測試和單元測試,本文通過示例代碼給大家介紹的非常詳細,感興趣的朋友跟隨小編一起看看吧
    2024-08-08
  • java反射獲取方法參數(shù)名的幾種方式總結(jié)

    java反射獲取方法參數(shù)名的幾種方式總結(jié)

    這篇文章主要介紹了如何通過添加編譯參數(shù)或使用Spring的工具類來獲取方法參數(shù)名,還總結(jié)了不同版本的JDK和Spring項目中參數(shù)名獲取的優(yōu)缺點,并提供了應(yīng)用場景舉例,需要的朋友可以參考下
    2025-02-02
  • Druid核心源碼解析DruidDataSource

    Druid核心源碼解析DruidDataSource

    這篇文章主要為大家介紹了Druid核心源碼解析DruidDataSource,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪
    2023-03-03
  • 詳解Java中String類的各種用法

    詳解Java中String類的各種用法

    Java中定義了String和StringBuffer兩個類來封裝對字符串的各種操作,存放于java.lang包中,是Java語言的核心類,提供了字符串的比較、查找、截取、大小寫轉(zhuǎn)換等操作,無需導(dǎo)入即可直接使用它們。讓我們來詳細了解它吧
    2021-11-11
  • Spring?MVC基于注解的使用之JSON數(shù)據(jù)處理的方法

    Spring?MVC基于注解的使用之JSON數(shù)據(jù)處理的方法

    這篇文章主要介紹了Spring?MVC基于注解的使用JSON數(shù)據(jù)處理,json是一種輕量級的數(shù)據(jù)交換格式,是一種理想的數(shù)據(jù)交互語言,它易于閱讀和編寫,同時也易于機器解析和生成,本文通過實例代碼給大家介紹的非常詳細,需要的朋友可以參考下
    2022-05-05
  • Spring注入方式與原理分析

    Spring注入方式與原理分析

    本文介紹了Spring框架中的依賴注入(DI)機制,包括基于XML和注解的依賴注入方式,如構(gòu)造器注入、setter注入和基于屬性(字段)注入,還討論了如何解決接口多實現(xiàn)類的注入問題,以及如何通過applicationContext手動獲取bean
    2026-05-05

最新評論

乌兰浩特市| 崇义县| 内江市| 北辰区| 罗江县| 桐柏县| 南投市| 城步| 巴中市| 汕头市| 天津市| 镇康县| 习水县| 固阳县| 保康县| 富宁县| 景东| 凌云县| 灌云县| 太保市| 巴青县| 兰考县| 米林县| 锦屏县| 防城港市| 息烽县| 郁南县| 外汇| 洪雅县| 凉山| 米易县| 绥棱县| 手游| 常州市| 乳源| 双鸭山市| 枣强县| 邢台县| 奉节县| 黔江区| 上栗县|