Mybatis-Plus大批量插入数据到MySQL

news2024/11/30 14:44:27

MyBatis-Plus的saveBatch方法

@GetMapping("/save1")
public void save1() {
    // 数据准备
    List<MallOrder> orderList = getMallOrderList();

    // mybatis-plus
    long start = System.currentTimeMillis();
    mallOrderService.saveBatch(orderList);
    System.out.println("mybatis-plus的【savaBatch】插入数据,耗时:" + (System.currentTimeMillis() - start) + "ms");
}

MyBatis-Plus的xml方式

@GetMapping("/save2")
public void save2() {
    // 数据准备
    List<MallOrder> orderList = getMallOrderList();

    // xml
    long start = System.currentTimeMillis();
    mallOrderService.saveBatchXml(orderList);
    System.out.println("mybatis-plus的【xml拼接sql】插入数据,耗时:" + (System.currentTimeMillis() - start) + "ms");
}
<insert id="saveBatch">
    insert into mall_order (order_id,
    customer_id,
    order_status,
    payment_method,
    total_amount,
    shipping_fee,
    coupon_discount,
    order_date,
    payment_time,
    shipping_address,
    receiver_name,
    receiver_phone)
    values
    <foreach collection="orderList" item="item" separator=",">
        (#{item.orderId},
        #{item.customerId},
        #{item.orderStatus},
        #{item.paymentMethod},
        #{item.totalAmount},
        #{item.shippingFee},
        #{item.couponDiscount},
        #{item.orderDate},
        #{item.paymentTime},
        #{item.shippingAddress},
        #{item.receiverName},
        #{item.receiverPhone})
    </foreach>
</insert>

MyBatis-Plus的批量插入器

@GetMapping("/save3")
public void save3() {
    // 数据准备
    List<MallOrder> orderList = getMallOrderList();

    // insertBatchSomeColumn
    long start = System.currentTimeMillis();
    mallOrderService.insertBatchSomeColumn(orderList);
    System.out.println("mybatis-plus的【insertBatchSomeColumn】插入数据,耗时:" + (System.currentTimeMillis() - start) + "ms");
}
package com.qiangesoft.batchsave.config;

import com.baomidou.mybatisplus.core.injector.AbstractMethod;
import com.baomidou.mybatisplus.core.injector.DefaultSqlInjector;
import com.baomidou.mybatisplus.core.metadata.TableInfo;
import com.baomidou.mybatisplus.extension.injector.methods.InsertBatchSomeColumn;

import java.util.List;

/**
 * sql注入器
 *
 * @author qiangesoft
 * @date 2024-04-11
 */
public class InsertBatchSqlInjector extends DefaultSqlInjector {

    @Override
    public List<AbstractMethod> getMethodList(Class<?> mapperClass, TableInfo tableInfo) {
        // super.getMethodList() 保留 Mybatis Plus 自带的方法
        List<AbstractMethod> methodList = super.getMethodList(mapperClass, tableInfo);
        // 添加自定义方法:批量插入,方法名为 insertBatchSomeColumn
        // bean mapper中的方法名也是insertBatchSomeColumn 须和内部定义好的方法名保持一致。
        methodList.add(new InsertBatchSomeColumn());
        return methodList;
    }

}
package com.qiangesoft.batchsave.config;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

/**
 * mybatis-plus配置
 *
 * @author qiangesoft
 * @date 2024-04-11
 */
@Configuration
public class MybatisPlusConfig {

    @Bean
    public InsertBatchSqlInjector insertBatchSqlInjector() {
        return new InsertBatchSqlInjector();
    }

}

package com.qiangesoft.batchsave.mapper;

import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.qiangesoft.batchsave.entity.MallOrder;
import org.apache.ibatis.annotations.Param;

import java.util.List;

/**
 * <p>
 * 订单信息表 Mapper 接口
 * </p>
 *
 * @author qiangesoft
 * @since 2024-05-07
 */
public interface MallOrderMapper extends BaseMapper<MallOrder> {

    /**
     * 批量插入 仅适用于mysql
     *
     * @param orderList
     */
    Integer insertBatchSomeColumn(List<MallOrder> orderList);
}

SqlSession手动提交

@GetMapping("/save4")
public void save4() {
    // 数据准备
    List<MallOrder> orderList = getMallOrderList();

    // 手动提交
    long start = System.currentTimeMillis();
    mallOrderService.manualCommit(orderList);
    System.out.println("sqlSession的【手动提交】插入数据100000条,耗时:" + (System.currentTimeMillis() - start) + "ms");
}
@Autowired
private SqlSessionFactory sqlSessionFactory;

@Override
public void manualCommit(List<MallOrder> orderList) {
    // 关闭自动提交
    SqlSession sqlSession = sqlSessionFactory.openSession(ExecutorType.BATCH, false);
    MallOrderMapper mallOrderMapper = sqlSession.getMapper(MallOrderMapper.class);
    for (MallOrder mallOrder : orderList) {
        mallOrderMapper.insert(mallOrder);
    }

    sqlSession.commit();
    sqlSession.clearCache();
    sqlSession.close();
}

循环执行MyBatis-Plus的save方法

@GetMapping("/save5")
public void save5() {
    // 数据准备
    List<MallOrder> orderList = getMallOrderList();

    // 循环插入
    long start = System.currentTimeMillis();
    for (MallOrder mallOrder : orderList) {
        mallOrderService.save(mallOrder);
    }
    System.out.println("mybatis-plus的【循环】插入数据100000条,耗时:" + (System.currentTimeMillis() - start) + "ms");
}

Statement批量执行

@GetMapping("/save6")
public void save6() {
    // 数据准备
    List<MallOrder> orderList = getMallOrderList();

    // statement.executeBatch
    long start = System.currentTimeMillis();
    mallOrderService.executeBatch(orderList);
    System.out.println("statement的【executeBatch】插入数据100000条,耗时:" + (System.currentTimeMillis() - start) + "ms");
}
@Override
public void executeBatch(List<MallOrder> orderList) {
    String sql = "insert into mall_order (" +
            "customer_id," +
            "order_status," +
            "payment_method," +
            "total_amount," +
            "shipping_fee," +
            "coupon_discount," +
            "order_date," +
            "payment_time," +
            "shipping_address," +
            "receiver_name," +
            "receiver_phone) values (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?);";

    SqlSession sqlSession = null;
    Connection connection = null;
    PreparedStatement statement = null;
    try {
        sqlSession = sqlSessionFactory.openSession();
        connection = sqlSession.getConnection();
        connection.setAutoCommit(false);
        statement = connection.prepareStatement(sql);

        for (MallOrder mallOrder : orderList) {
            // 主键自增不设置
//                statement.setLong(0, mallOrder.getOrderId());
            statement.setLong(1, mallOrder.getCustomerId());
            statement.setInt(2, mallOrder.getOrderStatus());
            statement.setInt(3, mallOrder.getPaymentMethod());
            statement.setBigDecimal(4, mallOrder.getTotalAmount());
            statement.setBigDecimal(5, mallOrder.getShippingFee());
            statement.setBigDecimal(6, mallOrder.getCouponDiscount());
            statement.setObject(7, mallOrder.getOrderDate());
            statement.setObject(8, mallOrder.getPaymentTime());
            statement.setString(9, mallOrder.getShippingAddress());
            statement.setString(10, mallOrder.getReceiverName());
            statement.setString(11, mallOrder.getReceiverPhone());
            statement.addBatch();
        }
        statement.executeBatch();
        connection.commit();
    } catch (SQLException e) {
        throw new RuntimeException(e);
    } finally {
        if (statement != null) {
            try {
                statement.close();
            } catch (SQLException e) {
                throw new RuntimeException(e);
            }
        }
        if (connection != null) {
            try {
                connection.close();
            } catch (SQLException e) {
                throw new RuntimeException(e);
            }
        }
        if (sqlSession != null) {
            sqlSession.close();
        }
    }
}

MyBatis-Plus的saveBatch方法+异步任务

@GetMapping("/save7")
public void save7() {
    // 数据准备
    List<MallOrder> orderList = getMallOrderList();

    // 异步任务处理
    long start = System.currentTimeMillis();
    mallOrderService.saveBatchAsync(orderList);
    System.out.println("mybatis-plus的【异步任务处理】插入数据100000条,耗时:" + (System.currentTimeMillis() - start) + "ms");
}
@Autowired
private ThreadPoolTaskExecutor threadPoolTaskExecutor;
@Autowired
private PlatformTransactionManager transactionManager;

@Override
public void saveBatchAsync(List<MallOrder> orderList) {
    int count = orderList.size();
    // 每批次插入的数据量
    int pageSize = 1000;
    // 线程数
    int threadNum = count % pageSize == 0 ? (count / pageSize) : (count / pageSize + 1);
    CountDownLatch countDownLatch = new CountDownLatch(threadNum);

    for (int i = 0; i < threadNum; i++) {
        int startIndex = i * pageSize;
        int endIndex = Math.min(count, (i + 1) * pageSize);
        List<MallOrder> subList = orderList.subList(startIndex, endIndex);
        threadPoolTaskExecutor.execute(() -> {
            DefaultTransactionDefinition transactionDefinition = new DefaultTransactionDefinition();
            TransactionStatus status = transactionManager.getTransaction(transactionDefinition);
            try {
                // 保存数据
                this.saveBatch(subList);
                transactionManager.commit(status);
            } catch (Exception exception) {
                transactionManager.rollback(status);
                throw exception;
            } finally {
                countDownLatch.countDown();
            }
        });
    }
    try {
        countDownLatch.await();
    } catch (InterruptedException e) {
        throw new RuntimeException(e);
    }
}

测试

CREATE TABLE `mall_order`
(
    `order_id`         BIGINT         NOT NULL AUTO_INCREMENT COMMENT '订单ID(主键)',
    `customer_id`      BIGINT         NOT NULL COMMENT '客户ID(关联customer表)',
    `order_status`     tinyint(4)     NOT NULL DEFAULT 1 COMMENT '订单状态 1-待支付 2-已支付 3-待发货 4-已发货 5-已完成 6-已取消',
    `payment_method`   tinyint(4)     NULL     DEFAULT null COMMENT '支付方式; 1-现金 2-支付宝 3-微信 4-银行卡',
    `total_amount`     DECIMAL(10, 2) NOT NULL COMMENT '订单总金额',
    `shipping_fee`     DECIMAL(10, 2) NOT NULL DEFAULT 0 COMMENT '运费',
    `coupon_discount`  DECIMAL(10, 2) NOT NULL DEFAULT 0 COMMENT '优惠券减免金额',
    `order_date`       DATETIME       NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '下单日期',
    `payment_time`     DATETIME                DEFAULT NULL COMMENT '支付时间',
    `shipping_address` VARCHAR(255)   NULL COMMENT '收货地址',
    `receiver_name`    VARCHAR(50)    NULL COMMENT '收货人姓名',
    `receiver_phone`   VARCHAR(20)    NULL COMMENT '收货人电话',
    PRIMARY KEY (`order_id`)
) ENGINE = InnoDB
  DEFAULT CHARSET = utf8mb4 COMMENT ='订单信息表';
package com.qiangesoft.batchsave.entity;

import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import java.io.Serializable;
import java.math.BigDecimal;
import java.time.LocalDateTime;
import lombok.Getter;
import lombok.Setter;
import lombok.experimental.Accessors;

/**
 * <p>
 * 订单信息表
 * </p>
 *
 * @author qiangesoft
 * @since 2024-05-07
 */
@Getter
@Setter
@Accessors(chain = true)
@TableName("mall_order")
public class MallOrder implements Serializable {

    private static final long serialVersionUID = 1L;

    /**
     * 订单ID(主键)
     */
    @TableId(value = "order_id", type = IdType.INPUT)
    private Long orderId;

    /**
     * 客户ID(关联customer表)
     */
    private Long customerId;

    /**
     * 订单状态 1-待支付 2-已支付 3-待发货 4-已发货 5-已完成 6-已取消
     */
    private Integer orderStatus;

    /**
     * 支付方式; 1-现金 2-支付宝 3-微信 4-银行卡
     */
    private Integer paymentMethod;

    /**
     * 订单总金额
     */
    private BigDecimal totalAmount;

    /**
     * 运费
     */
    private BigDecimal shippingFee;

    /**
     * 优惠券减免金额
     */
    private BigDecimal couponDiscount;

    /**
     * 下单日期
     */
    private LocalDateTime orderDate;

    /**
     * 支付时间
     */
    private LocalDateTime paymentTime;

    /**
     * 收货地址
     */
    private String shippingAddress;

    /**
     * 收货人姓名
     */
    private String receiverName;

    /**
     * 收货人电话
     */
    private String receiverPhone;


}

1000条

/**
 * 构建数据
 *
 * @return
 */
private static List<MallOrder> getMallOrderList() {
    List<MallOrder> orderList = new ArrayList<>();
    for (int i = 0; i < 10000; i++) {
        MallOrder mallOrder = new MallOrder();
        mallOrder.setCustomerId(1L);
        mallOrder.setOrderStatus(1);
        mallOrder.setPaymentMethod(1);
        mallOrder.setTotalAmount(BigDecimal.valueOf(12));
        mallOrder.setShippingFee(BigDecimal.valueOf(1));
        mallOrder.setCouponDiscount(BigDecimal.valueOf(0));
        mallOrder.setOrderDate(LocalDateTime.now());
        mallOrder.setPaymentTime(LocalDateTime.now());
        mallOrder.setShippingAddress("哈哈");
        mallOrder.setReceiverName("暂时");
        mallOrder.setReceiverPhone("13211111111");
        orderList.add(mallOrder);
    }
    return orderList;
}

在这里插入图片描述

10000条

/**
 * 构建数据
 *
 * @return
 */
private static List<MallOrder> getMallOrderList() {
    List<MallOrder> orderList = new ArrayList<>();
    for (int i = 0; i < 1000; i++) {
        MallOrder mallOrder = new MallOrder();
        mallOrder.setCustomerId(1L);
        mallOrder.setOrderStatus(1);
        mallOrder.setPaymentMethod(1);
        mallOrder.setTotalAmount(BigDecimal.valueOf(12));
        mallOrder.setShippingFee(BigDecimal.valueOf(1));
        mallOrder.setCouponDiscount(BigDecimal.valueOf(0));
        mallOrder.setOrderDate(LocalDateTime.now());
        mallOrder.setPaymentTime(LocalDateTime.now());
        mallOrder.setShippingAddress("哈哈");
        mallOrder.setReceiverName("暂时");
        mallOrder.setReceiverPhone("13211111111");
        orderList.add(mallOrder);
    }
    return orderList;
}

在这里插入图片描述

总结

由此可见:
MyBatis-Plus的批量插入器、Statement批量执行、MyBatis-Plus的saveBatch方法+异步任务这三种方式较快。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1667742.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

java中EQ、NE、GE、GT、LE、LT

关系运算符 包括EQ、NE、GE、GT、LE、LT几个&#xff0c;关系运算符返回的是真“True”或假“False”。 eq&#xff08;Equal to&#xff09; 等 运算符 &#xff0c;如果运算符两边相同则返回真&#xff0c;否则返回假&#xff1b; ne&#xff08;Not Equal to&#xff09; 不…

美术:模型动画

游戏模型制作流程&#xff0c;SP和BP根据情况来选择软件对UV进行处理 3Dmax 制作模型和动画&#xff08;橘肉&#xff09;RizomUV 对模型进行展UV&#xff08;橘皮&#xff09;Substance Painter 纹理手绘&#xff08;给橘皮制定想要的皮肤&#xff09;BodyPaint 3D 纹理手绘&a…

Hive Transaction事务表(含实现原理)

Hive Transaction事务表 在Hive中&#xff0c;事务表&#xff08;Transactional Tables&#xff09;允许用户执行事务性操作&#xff0c;包括ACID&#xff08;原子性、一致性、隔离性、持久性&#xff09;特性。事务表是在Hive 0.14版本引入的&#xff0c;并且在后续版本中不断…

最新的云渲染100活动有哪些?渲染100邀请码1a12

随着科技的进步&#xff0c;云渲染已经成为设计行业的必备工具&#xff0c;各个云渲染平台为了吸引用户也推出各种各样的活动&#xff0c;今天我们以广受好评的渲染100为例&#xff0c;来说下它们的活动体系。 1、新用户活动 渲染100对新用户很友好&#xff0c;提供了充足的测…

PyTorch的卷积和池化

卷积计算 input 表示输入的图像filter 表示卷积核, 也叫做滤波器input 经过 filter 的得到输出为最右侧的图像&#xff0c;该图叫做特征图 卷积的计算是将卷积核放入左上角&#xff0c;在局部区域间做点积&#xff0c;然后将卷积核在Input上面依次从左向右&#xff0c;从上到下…

STM32串口通信入门

文章目录 一、串口协议和RS-232标准&#xff0c;以及RS232电平与TTL电平的区别1.串口通信协议2.RS-232标准3.RS232电平与TTL电平的区别4.USB/TTL转232“模块&#xff08;CH340芯片为例&#xff09; 二、补充实验&#xff08;一&#xff09;几个常见的库函数、结构体1.时钟配置函…

LeetCode—用队列实现栈

一.题目 二.思路 1.后入先出的实现&#xff1a; 创建两个队列来实现栈&#xff08;后入先出&#xff09;&#xff1a; 两个队列&#xff0c;保持一个存数据&#xff0c;另一个为空&#xff0c;入数据&#xff08;push&#xff09;要入不为空的队列&#xff0c;&#xff08;p…

深圳晶彩智能ESP32-1732S019实时观看GPIO的状态

深圳晶彩智能ESP32-1732S019介绍 ESP32-1732S019开发板是基于ESP32-S3-WROOM-1模块作为主控&#xff0c;双核MCU ,集成WI-FI和蓝牙功能&#xff0c;主控频率可达240MHz , 512KB SRAM , 384KB ROM&#xff0c;8M PSRAM&#xff0c;16MB Flash&#xff0c;显示分辨率为170*320 I…

冯喜运:5.12黄金回撤继续上涨,下周原油走势分析

【黄金消息面分析】&#xff1a;本周&#xff0c;黄金市场迎来了自4月中旬以来的最佳单周表现。周五&#xff08;3月9日&#xff09;&#xff0c;金价攀升至2360.54美元/盎司&#xff0c;涨幅0.62%&#xff0c;而纽约商品交易所6月交割的黄金期货价格上涨1.5%&#xff0c;收报2…

Springboot+Vue项目-基于Java+MySQL的毕业就业信息管理系统(附源码+演示视频+LW)

大家好&#xff01;我是程序猿老A&#xff0c;感谢您阅读本文&#xff0c;欢迎一键三连哦。 &#x1f49e;当前专栏&#xff1a;Java毕业设计 精彩专栏推荐&#x1f447;&#x1f3fb;&#x1f447;&#x1f3fb;&#x1f447;&#x1f3fb; &#x1f380; Python毕业设计 &…

其他的 框架安全:Apache Shiro 漏洞序列.(CVE-2016-2807)

什么是 Apache Shiro Apache Shiro 是一个强大且易用的Java安全框架&#xff0c;它为应用程序提供了身份验证、授权、加密和会话管理等常见的安全功能。漏洞大多会发生在登录处&#xff0c;返回包里包含remeberMedeleteMe字段.&#xff08; Shiro 这个属于第三方的&#xff0c…

表的创建与操作表

1. 创建表 创建表有两种方式 : 一种是白手起家自己添&#xff0c;一种是富二代直接继承. 2. 创建方式1 (1). 必须具备条件 CREATE TABLE权限存储空间 (2). 语法格式 CREATE TABLE IF NOT EXISTS 表名(字段1, 数据类型 [约束条件] [默认值],字段2, 数据类型 [约束条件] [默…

Spring高手之路18——从XML配置角度理解Spring AOP

文章目录 1. Spring AOP与动态代理1.1 Spring AOP和动态代理的关系1.2 AOP基本术语 2. 通过XML配置实现Spring AOP2.1 添加Spring依赖2.2 定义业务接口和实现类2.3 定义切面类2.4 配置XML 1. Spring AOP与动态代理 1.1 Spring AOP和动态代理的关系 Spring AOP使用动态代理作为…

用 Python 和 AkShare 进行个股数据清洗:简易多功能方法

标题:用 Python 和 AkShare 进行个股数据清洗:简易多功能方法 简介: 本文介绍了如何使用 Python 和 AkShare 库对个股数据进行清洗和处理。个股数据经常需要进行清洗以用于分析、建模或可视化。我们将介绍一些简单但功能强大的方法,包括数据加载、缺失值处理、重复值检测和…

Gitlab:从其它项目组里导入一个项目

1.首先获取原项目的http地址 http://ip/projectGroup/ProjectX.git其中&#xff0c;ip 为公司gitlab内网地址。 2.进入目的项目组进行创建 首先&#xff0c;需要拥有一个该组拥有者权限的账号&#xff0c;才能进行后续的操作。 2.1.点击创建项目按钮 2.2.选择导入项目 其中…

03c++重载运算符

1、深入理解new和delete原理 #include<iostream> using namespace std;/* new 和 delete 1、malloc和new的区别 new 内存开辟构造函数 2、free和 delete的区别 delete 内存回收析构函数 开辟失败malloc返nullptr ,new抛出bad_alloc异常new->operator new delete -&…

Docker学习(带图详细)

一、安装docker 参考官方文档&#xff1a;https://docs.docker.com/engine/install/centos/ 查看系统版本 [rootlocalhost ~]# cat /etc/redhat-release CentOS Linux release 7.9.2009 (Core) [rootlocalhost ~]# [rootlocalhost ~]# uname -a Linux localhost.localdomai…

STM32平衡车-MPU6050的DMP库移植

本文目录 一、硬件接线二、需要移植的三个文件夹1. DMP文件夹目录2. IIC文件夹目录3. MPU6050文件夹目录 三、文件内容IO12C.cIO12C.hMPU6050.cMPU6050.hmain.c 四、附录1.更改IIC引脚 一、硬件接线 SCL-- PA11 SDA-- PA12 VCC-- 3.3v GND-- GND INT-- PC9 二、需要移植的三个…

[Kubernetes] Istio on Kubernetes 实践

文章目录 1.Kubernetes 创建2.Istio 部署2.1 下载 Istio2.2 安装 Istio 3.Istio on Kubernetes 实践3.1 部署 Bookinfo 示例应用3.2 确定入站 IP 和端口 1.Kubernetes 创建 主机名内部ip外部ipmaster192.168.66.2139.198.36.40node1192.168.66.3139.198.1.192node2192.168.66.…

数据结构——栈与队列的专题

文章目录 前言一、用队列实现栈二、用栈实现队列三、设计循环队列 前言 本篇是围绕栈与队列来展开&#xff0c;需要知道一定有关它们的相关基础知识 栈的详解 队列的详解 还有一道基础的栈题——有效的括号 一、用队列实现栈 原题链接&#xff1a;用队列实现栈 解题思路&a…