日本综合一区二区|亚洲中文天堂综合|日韩欧美自拍一区|男女精品天堂一区|欧美自拍第6页亚洲成人精品一区|亚洲黄色天堂一区二区成人|超碰91偷拍第一页|日韩av夜夜嗨中文字幕|久久蜜综合视频官网|精美人妻一区二区三区

RELATEED CONSULTING
相關(guān)咨詢
選擇下列產(chǎn)品馬上在線溝通
服務(wù)時間:8:30-17:00
你可能遇到了下面的問題
關(guān)閉右側(cè)工具欄

新聞中心

這里有您想知道的互聯(lián)網(wǎng)營銷解決方案
MyBatis批量插入數(shù)據(jù)優(yōu)化,那叫一個優(yōu)雅!

在項目開發(fā)中,我們經(jīng)常需要進行大量數(shù)據(jù)的批量插入操作。然而,在實際應(yīng)用中,插入大量數(shù)據(jù)時性能常常成為一個瓶頸。在我最近的項目中,我發(fā)現(xiàn)了一些能夠顯著提升批量插入性能的方法,并進行了一系列實驗來驗證它們的有效性。

網(wǎng)站建設(shè)哪家好,找創(chuàng)新互聯(lián)公司!專注于網(wǎng)頁設(shè)計、網(wǎng)站建設(shè)、微信開發(fā)、成都小程序開發(fā)、集團企業(yè)網(wǎng)站建設(shè)等服務(wù)項目。為回饋新老客戶創(chuàng)新互聯(lián)還提供了港閘免費建站歡迎大家使用!

今日內(nèi)容介紹,大約花費15分鐘

圖片

背景介紹

我們使用了 mybatis-plus 框架,并采用其中的 saveBatch 方法進行批量數(shù)據(jù)插入。然而,通過深入研究源碼,我發(fā)現(xiàn)這個方法并沒有如我期望的那樣高效

圖片

這是因為最終在執(zhí)行的時候還是通過for循環(huán)一條條執(zhí)行insert,然后再一批的進行flush ,默認批的消息為1000

圖片

為了找到更優(yōu)秀的解決方案,我展開了一場性能優(yōu)化的探索之旅。好了我們現(xiàn)在開始探索

實驗準備

  • 創(chuàng)建一張表tb_student
create table springboot_mp.tb_student
(
    id      bigint auto_increment comment '主鍵ID'
        primary key,
    stuid   varchar(40)   not null comment '學號',
    name    varchar(30)   null comment '姓名',
    age     tinyint       null comment '年齡',
    sex     tinyint(1)    null comment '性別 0 男 1 女',
    dept    varchar(2000) null comment '院系',
    address varchar(400)  null comment '家庭地址',
    constraint stuid
        unique (stuid)
);
  • 創(chuàng)建spring-boot-mybatis-demo項目并在pom.xml中添加依賴

圖片


    
        org.springframework.boot
        spring-boot-starter-web
    

    
        org.springframework.boot
        spring-boot-starter-test
    

    
        mysql
        mysql-connector-java
        8.0.30
    


    
        com.baomidou
        mybatis-plus-boot-starter
        3.5.3
    


    
        org.projectlombok
        lombok
    
  • application.yml配置
server:
  port: 8890

spring:
  application:
    name: mybatis-demo #指定服務(wù)名
  datasource:
    username: root
    password: root
#    url: jdbc:mysql://localhost:3306/springboot_mp?useUnicode=true&characterEncoding=utf8&rewriteBatchedStatements=true
    url: jdbc:mysql://localhost:3306/springboot_mp?useUnicode=true&characterEncoding=utf8
    driver-class-name: com.mysql.cj.jdbc.Driver
#
mybatis-plus:
  configuration:
    log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
  mapper-locations: classpath*:/mapper/**/*.xml
  • 使用mybatisX生成代碼

圖片

圖片

圖片

探索實驗

每次都是插入100000條數(shù)據(jù)

注意:因為我的電腦性能比較好,所以才插入這么多數(shù)據(jù),大家可以插入1000進行實驗對比

  1. 單條循環(huán)插入:傳統(tǒng)方法的基準

首先,我采用了傳統(tǒng)的單條循環(huán)插入方法,將每條數(shù)據(jù)逐一插入數(shù)據(jù)庫,作為性能對比的基準。

/**
 * @author springboot葵花寶典
 * @description: TODO
 */
@SpringBootTest
public class MybatisTest {

    @Autowired
    private StudentService studentService;

    @Autowired
    private SqlSessionFactory sqlSessionFactory;

    @Test
    public void MybatisBatchSaveOneByOne(){


        SqlSession sqlSession = sqlSessionFactory.openSession();

        try {
            StopWatch stopWatch = new StopWatch();
            stopWatch.start("mybatis plus save one");
            for (int i = 0; i < 100000; i++) {
                Student student = new Student();
                student.setStuid("6840"+i);
                student.setName("zhangsan"+i);

                student.setAge((i%100));


                if(i%2==0){
                    student.setSex(0);
                }else {
                    student.setSex(1);
                }

                student.setDept("計算機學院");
                student.setAddress("廣東省廣州市番禺"+i+"號");
                //一條一條插入
                studentService.save(student);
            }
            sqlSession.commit();
            stopWatch.stop();
            System.out.println("mybatis plus save one:" + stopWatch.getTotalTimeMillis());

        } finally {
            sqlSession.close();
        }

    }

}

發(fā)現(xiàn)花費了195569毫秒

圖片

  1. mybatis-plus 的 saveBatch 方法

現(xiàn)在嘗試 mybatis-plus 提供的 saveBatch 方法,期望它能夠提高性能。

@Test
    public void MybatissaveBatch(){


        SqlSession sqlSession = sqlSessionFactory.openSession();

        try {

            List students = new ArrayList<>();
            StopWatch stopWatch = new StopWatch();

            stopWatch.start("mybatis plus save batch");
            for (int i = 0; i < 100000; i++) {
                Student student = new Student();
                student.setStuid("6840"+i);
                student.setName("zhangsan"+i);

                student.setAge((i%100));


                if(i%2==0){
                    student.setSex(0);
                }else {
                    student.setSex(1);
                }

                student.setDept("計算機學院");
                student.setAddress("廣東省廣州市番禺"+i+"號");
                //一條一條插入
                students.add(student);
            }

            studentService.saveBatch(students);
            sqlSession.commit();
            stopWatch.stop();
            System.out.println("mybatis plus save batch:" + stopWatch.getTotalTimeMillis());

        } finally {
            sqlSession.close();
        }

    }

發(fā)現(xiàn)花費9204毫秒,比一條條插入數(shù)據(jù)性能提高十幾倍

3.手動拼接 SQL:挑戰(zhàn)傳統(tǒng)的方式


    insert into springboot_mp.tb_student ( stuid, name, age, sex, dept, address)
    values
    
          ( #{stu.stuid}, #{stu.name}, #{stu.age}, #{stu.sex}, #{stu.dept}, #{stu.address})
    

發(fā)現(xiàn)花費10958毫秒,比一條條插入數(shù)據(jù)性能提高十幾倍,但是和saveBatch性能相差不大

既然都驗證都這了,我就在想,要不要使用JDBC批量插入進行驗證一下,看會不會出現(xiàn)原始的才是最好的結(jié)果

4.JDBC 的 executeBatch 方法

嘗試直接使用 JDBC 提供的 executeBatch 方法,看是否有意外的性能提升。

@Test
    public void JDBCSaveBatch() throws SQLException {


        SqlSession sqlSession = sqlSessionFactory.openSession();
        Connection connection = sqlSession.getConnection();
        connection.setAutoCommit(false);



        String sql ="insert into springboot_mp.tb_student ( stuid, name, age, sex, dept, address) values (?, ?, ?, ?, ?, ?);";
        try (PreparedStatement statement = connection.prepareStatement(sql)) {

            List students = new ArrayList<>();
            StopWatch stopWatch = new StopWatch();
            stopWatch.start("mybatis plus JDBCSaveBatch");
            for (int i = 0; i < 100000; i++) {
                statement.setString(1,"6840"+i);
                statement.setString(2,"zhangsan"+i);
                statement.setInt(3,(i%100));
                if(i%2==0){
                    statement.setInt(4,0);
                }else {
                    statement.setInt(4,1);
                }
                statement.setString(5,"計算機學院");
                statement.setString(6,"廣東省廣州市番禺"+i+"號");


                statement.addBatch();
            }

            statement.executeBatch();
            connection.commit();
            stopWatch.stop();
            System.out.println("mybatis plus JDBCSaveBatch:" + stopWatch.getTotalTimeMillis());

        }
        catch (Exception e){
            System.out.println(e.getMessage());
        }
        finally {

            sqlSession.close();
        }

JDBC executeBatch 的性能會好點,耗費6667毫秒

但是感覺到這里以后,覺得時候還是比較長,有沒有可以再進行優(yōu)化的方式,然后我就在ClientPreparedStatement類中發(fā)現(xiàn)有一個叫做rewriteBatchedStatements 的屬性,從名字來看是要重寫批操作的 Statement,前面batchHasPlainStatements 已經(jīng)是 false,取反肯定是 true,所以只要這參數(shù)是 true 就會進行一波操作。rewriteBatchedStatements默認是 false。

圖片

圖片

大家也可以自行網(wǎng)上搜索一下這個神奇的屬性然后我在url添加上這個屬性

圖片

然后繼續(xù)跑了下 mybatis-plus 自帶的 saveBatch,果然性能大大提高直接由原來的9204毫秒,提升到現(xiàn)在的3903毫秒

圖片

再來跑一下JDBC 的 executeBatch ,果然也提高了。

直接由原來的6667毫秒,提升到了3794毫秒

結(jié)果對比

批量保存方式

數(shù)據(jù)量(條)

耗時(ms)

單條循環(huán)插入

100000

195569

mybatis-plus saveBatch

100000

9204

mybatis-plus saveBatch(添加 rewrite 參數(shù))

100000

3903

手動拼接 SQL

100000

6667

JDBC executeBatch

100000

10958

JDBC executeBatch(添加 rewrite 參數(shù))

100000

3794

結(jié)論

通過實驗結(jié)果,我們可以得出以下結(jié)論:

  • mybatis-plus 的 saveBatch 方法相比單條循環(huán)插入在性能上有所提升,但仍然不夠理想。
  • JDBC 的 executeBatch 方法在默認情況下性能與 mybatis-plus 的 saveBatch 類似,但通過設(shè)置 rewriteBatchedStatements 參數(shù)為 true 可顯著提高性能。
  • rewriteBatchedStatements 參數(shù)的作用是將一批插入拼接成 insert into xxx values (a),(b),(c)... 這樣的一條語句形式,提高了性能。

優(yōu)化建議

如果您在項目中需要進行批量插入操作,我建議考慮以下優(yōu)化方案:

  • 如果使用 mybatis-plus,可以嘗試將 JDBC 連接字符串中的 rewriteBatchedStatements 參數(shù)設(shè)置為 true,以提高 saveBatch 方法的性能。

文章題目:MyBatis批量插入數(shù)據(jù)優(yōu)化,那叫一個優(yōu)雅!
網(wǎng)站地址:http://www.dlmjj.cn/article/djchgij.html