日韩成人免费在线_国产成人一二_精品国产免费人成电影在线观..._日本一区二区三区久久久久久久久不

當(dāng)前位置:首頁 > 科技  > 軟件

MyBatis批量插入數(shù)據(jù)優(yōu)化,那叫一個優(yōu)雅!

來源: 責(zé)編: 時間:2024-01-02 09:30:34 198觀看
導(dǎo)讀在項(xiàng)目開發(fā)中,我們經(jīng)常需要進(jìn)行大量數(shù)據(jù)的批量插入操作。然而,在實(shí)際應(yīng)用中,插入大量數(shù)據(jù)時性能常常成為一個瓶頸。在我最近的項(xiàng)目中,我發(fā)現(xiàn)了一些能夠顯著提升批量插入性能的方法,并進(jìn)行了一系列實(shí)驗(yàn)來驗(yàn)證它們的有效性。

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

今日內(nèi)容介紹,大約花費(fèi)15分鐘dkY28資訊網(wǎng)——每日最新資訊28at.com

圖片圖片dkY28資訊網(wǎng)——每日最新資訊28at.com

背景介紹

我們使用了 mybatis-plus 框架,并采用其中的 saveBatch 方法進(jìn)行批量數(shù)據(jù)插入。然而,通過深入研究源碼,我發(fā)現(xiàn)這個方法并沒有如我期望的那樣高效dkY28資訊網(wǎng)——每日最新資訊28at.com

圖片圖片dkY28資訊網(wǎng)——每日最新資訊28at.com

這是因?yàn)樽罱K在執(zhí)行的時候還是通過for循環(huán)一條條執(zhí)行insert,然后再一批的進(jìn)行flush ,默認(rèn)批的消息為1000dkY28資訊網(wǎng)——每日最新資訊28at.com

圖片圖片dkY28資訊網(wǎng)——每日最新資訊28at.com

為了找到更優(yōu)秀的解決方案,我展開了一場性能優(yōu)化的探索之旅。好了我們現(xiàn)在開始探索dkY28資訊網(wǎng)——每日最新資訊28at.com

實(shí)驗(yàn)準(zhǔ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 '學(xué)號',    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項(xiàng)目并在pom.xml中添加依賴

圖片圖片dkY28資訊網(wǎng)——每日最新資訊28at.com

<dependencies>    <dependency>        <groupId>org.springframework.boot</groupId>        <artifactId>spring-boot-starter-web</artifactId>    </dependency>    <dependency>        <groupId>org.springframework.boot</groupId>        <artifactId>spring-boot-starter-test</artifactId>    </dependency>    <dependency>        <groupId>mysql</groupId>        <artifactId>mysql-connector-java</artifactId>        <version>8.0.30</version>    </dependency>    <dependency>        <groupId>com.baomidou</groupId>        <artifactId>mybatis-plus-boot-starter</artifactId>        <version>3.5.3</version>    </dependency>    <dependency>        <groupId>org.projectlombok</groupId>        <artifactId>lombok</artifactId>    </dependency></dependencies>
  • application.yml配置
server:  port: 8890spring:  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生成代碼

圖片圖片dkY28資訊網(wǎng)——每日最新資訊28at.com

圖片圖片dkY28資訊網(wǎng)——每日最新資訊28at.com

圖片圖片dkY28資訊網(wǎng)——每日最新資訊28at.com

探索實(shí)驗(yàn)

每次都是插入100000條數(shù)據(jù)dkY28資訊網(wǎng)——每日最新資訊28at.com

注意:因?yàn)槲业碾娔X性能比較好,所以才插入這么多數(shù)據(jù),大家可以插入1000進(jìn)行實(shí)驗(yàn)對比dkY28資訊網(wǎng)——每日最新資訊28at.com

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

首先,我采用了傳統(tǒng)的單條循環(huán)插入方法,將每條數(shù)據(jù)逐一插入數(shù)據(jù)庫,作為性能對比的基準(zhǔn)。dkY28資訊網(wǎng)——每日最新資訊28at.com

/** * @author springboot葵花寶典 * @description: TODO */@SpringBootTestpublic 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("計(jì)算機(jī)學(xué)院");                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)花費(fèi)了195569毫秒dkY28資訊網(wǎng)——每日最新資訊28at.com

圖片圖片dkY28資訊網(wǎng)——每日最新資訊28at.com

  1. mybatis-plus 的 saveBatch 方法

現(xiàn)在嘗試 mybatis-plus 提供的 saveBatch 方法,期望它能夠提高性能。dkY28資訊網(wǎng)——每日最新資訊28at.com

@Test    public void MybatissaveBatch(){        SqlSession sqlSession = sqlSessionFactory.openSession();        try {            List<Student> 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("計(jì)算機(jī)學(xué)院");                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)花費(fèi)9204毫秒,比一條條插入數(shù)據(jù)性能提高十幾倍dkY28資訊網(wǎng)——每日最新資訊28at.com

圖片dkY28資訊網(wǎng)——每日最新資訊28at.com

3.手動拼接 SQL:挑戰(zhàn)傳統(tǒng)的方式dkY28資訊網(wǎng)——每日最新資訊28at.com

<insert id="saveBatch2">    insert into springboot_mp.tb_student ( stuid, name, age, sex, dept, address)    values    <foreach collection="students" item="stu" index="index" separator=",">          ( #{stu.stuid}, #{stu.name}, #{stu.age}, #{stu.sex}, #{stu.dept}, #{stu.address})    </foreach></insert>

發(fā)現(xiàn)花費(fèi)10958毫秒,比一條條插入數(shù)據(jù)性能提高十幾倍,但是和saveBatch性能相差不大dkY28資訊網(wǎng)——每日最新資訊28at.com

既然都驗(yàn)證都這了,我就在想,要不要使用JDBC批量插入進(jìn)行驗(yàn)證一下,看會不會出現(xiàn)原始的才是最好的結(jié)果dkY28資訊網(wǎng)——每日最新資訊28at.com

4.JDBC 的 executeBatch 方法dkY28資訊網(wǎng)——每日最新資訊28at.com

嘗試直接使用 JDBC 提供的 executeBatch 方法,看是否有意外的性能提升。dkY28資訊網(wǎng)——每日最新資訊28at.com

@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<Student> 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,"計(jì)算機(jī)學(xué)院");                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 的性能會好點(diǎn),耗費(fèi)6667毫秒dkY28資訊網(wǎng)——每日最新資訊28at.com

圖片dkY28資訊網(wǎng)——每日最新資訊28at.com

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

圖片圖片dkY28資訊網(wǎng)——每日最新資訊28at.com

圖片dkY28資訊網(wǎng)——每日最新資訊28at.com

圖片圖片dkY28資訊網(wǎng)——每日最新資訊28at.com

大家也可以自行網(wǎng)上搜索一下這個神奇的屬性然后我在url添加上這個屬性dkY28資訊網(wǎng)——每日最新資訊28at.com

圖片圖片dkY28資訊網(wǎng)——每日最新資訊28at.com

然后繼續(xù)跑了下 mybatis-plus 自帶的 saveBatch,果然性能大大提高直接由原來的9204毫秒,提升到現(xiàn)在的3903毫秒dkY28資訊網(wǎng)——每日最新資訊28at.com

圖片圖片dkY28資訊網(wǎng)——每日最新資訊28at.com

再來跑一下JDBC 的 executeBatch ,果然也提高了。dkY28資訊網(wǎng)——每日最新資訊28at.com

直接由原來的6667毫秒,提升到了3794毫秒dkY28資訊網(wǎng)——每日最新資訊28at.com

圖片dkY28資訊網(wǎng)——每日最新資訊28at.com

結(jié)果對比

批量保存方式
dkY28資訊網(wǎng)——每日最新資訊28at.com

數(shù)據(jù)量(條)
dkY28資訊網(wǎng)——每日最新資訊28at.com

耗時(ms)
dkY28資訊網(wǎng)——每日最新資訊28at.com

單條循環(huán)插入
dkY28資訊網(wǎng)——每日最新資訊28at.com

100000
dkY28資訊網(wǎng)——每日最新資訊28at.com

195569
dkY28資訊網(wǎng)——每日最新資訊28at.com

mybatis-plus saveBatch
dkY28資訊網(wǎng)——每日最新資訊28at.com


dkY28資訊網(wǎng)——每日最新資訊28at.com

100000
dkY28資訊網(wǎng)——每日最新資訊28at.com

9204
dkY28資訊網(wǎng)——每日最新資訊28at.com

mybatis-plus saveBatch(添加 rewrite 參數(shù))
dkY28資訊網(wǎng)——每日最新資訊28at.com

100000
dkY28資訊網(wǎng)——每日最新資訊28at.com

3903
dkY28資訊網(wǎng)——每日最新資訊28at.com

手動拼接 SQL
dkY28資訊網(wǎng)——每日最新資訊28at.com

100000
dkY28資訊網(wǎng)——每日最新資訊28at.com

6667
dkY28資訊網(wǎng)——每日最新資訊28at.com

JDBC executeBatch
dkY28資訊網(wǎng)——每日最新資訊28at.com

100000
dkY28資訊網(wǎng)——每日最新資訊28at.com

10958
dkY28資訊網(wǎng)——每日最新資訊28at.com

JDBC executeBatch(添加 rewrite 參數(shù))
dkY28資訊網(wǎng)——每日最新資訊28at.com

100000
dkY28資訊網(wǎng)——每日最新資訊28at.com

3794
dkY28資訊網(wǎng)——每日最新資訊28at.com

結(jié)論

通過實(shí)驗(yàn)結(jié)果,我們可以得出以下結(jié)論:dkY28資訊網(wǎng)——每日最新資訊28at.com

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

優(yōu)化建議

如果您在項(xiàng)目中需要進(jìn)行批量插入操作,我建議考慮以下優(yōu)化方案:dkY28資訊網(wǎng)——每日最新資訊28at.com

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

本文鏈接:http://www.www897cc.com/showinfo-26-55086-0.htmlMyBatis批量插入數(shù)據(jù)優(yōu)化,那叫一個優(yōu)雅!

聲明:本網(wǎng)頁內(nèi)容旨在傳播知識,若有侵權(quán)等問題請及時與本網(wǎng)聯(lián)系,我們將在第一時間刪除處理。郵件:2376512515@qq.com

上一篇: C++中的內(nèi)存管理:深入理解與應(yīng)用

下一篇: Go語言中的性能考慮和優(yōu)化

標(biāo)簽:
  • 熱門焦點(diǎn)
Top 主站蜘蛛池模板: 浑源县| 沙雅县| 新野县| 忻州市| 丹江口市| 盐亭县| 高平市| 海晏县| 临清市| 西乌珠穆沁旗| 上蔡县| 萨迦县| 丰县| 正安县| 卓尼县| 南投市| 阿克陶县| 长岛县| 平塘县| 宾川县| 积石山| 兴城市| 衡水市| 泽州县| 华池县| 宾川县| 平和县| 青浦区| 凤城市| 大理市| 济宁市| 抚顺市| 祥云县| 榆树市| 柞水县| 灯塔市| 邓州市| 师宗县| 浑源县| 淮南市| 绥阳县|