首页 > 编程语言 >Java批量插入数据方法对比

Java批量插入数据方法对比

时间:2023-09-09 23:12:45浏览次数:32  
标签:ps Java 批量 random System 插入 connection ex new

一.环境

  1. 数据库MySql 8.0.2
  2. Maven+IDEA

二.方法配置

  1. 目录结构

 

  1. POM.xml依赖

<dependencies>
    <!-- https://mvnrepository.com/artifact/mysql/mysql-connector-java -->
    <dependency>
        <groupId>mysql</groupId>
        <artifactId>mysql-connector-java</artifactId>
        <version>8.0.33</version>
    </dependency>
    <!-- https://mvnrepository.com/artifact/org.mybatis/mybatis -->
    <dependency>
        <groupId>org.mybatis</groupId>
        <artifactId>mybatis</artifactId>
        <version>3.5.13</version>
    </dependency>
    <!-- https://mvnrepository.com/artifact/junit/junit -->
    <dependency>
        <groupId>junit</groupId>
        <artifactId>junit</artifactId>
        <version>4.13.2</version>
        <scope>test</scope>
    </dependency>
</dependencies>

  1. Mybatis配置mybati-config.xml

<?xml version="1.0" encoding="UTF-8"?>

<!DOCTYPE configuration PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
        "<http://mybatis.org/dtd/mybatis-3-config.dtd>">
<configuration>
    <environments default="development">
        <environment id="development">
            <transactionManager type="JDBC"/>
            <dataSource type="POOLED">
                <property name="driver" value="com.mysql.cj.jdbc.Driver"/>
                <property name="url" value="jdbc:mysql://192.168.20.10:3306/SCTest?useSSL=false&amp;allowPublicKeyRetrieval=true&amp;serverTimezone=UTC&amp;rewriteBatchedStatements=true"/>
                <property name="username" value="root"/>
                <property name="password" value="17klop"/>
            </dataSource>
        </environment>
    </environments>
    <mappers>
        <mapper class="com.sc.common.IInsertMapper"/>
    </mappers>
</configuration>

  1. Mybatis Mapper代码(IInsertMapper)

package com.sc.common;

import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Select;

@Mapper
public interface IInsertMapper {
    @Select("insert into t_inserttest(IndexV)value(#{index})")
    void insertBatch(int index);
}

  1. 实现类源代码

package com.sc.common;

import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;

import java.io.InputStream;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.util.Random;

public class MySqlHelper {
    public MySqlHelper() {
        try {
            Class.forName("com.mysql.cj.jdbc.Driver");
        } catch (Exception ex) {
            System.out.println(ex.getMessage());
        }
    }

    //&rewriteBatchedStatements=true连接字符串必须添加这个配置,否则无法实现批量提交
    private static final String DB_URL = "jdbc:mysql://192.168.20.10:3306/SCTest?useSSL=false&allowPublicKeyRetrieval=true&serverTimezone=UTC&rewriteBatchedStatements=true";
    private static final String uid = "root";
    private static final String pwd = "17klop";
    private static final String insertSql="insert into t_inserttest(IndexV)value(?)";
    private static Connection connection = null;

    //1.测试连接
    public Boolean isConnect() throws Exception {
        try {
            connection = DriverManager.getConnection(DB_URL,uid,pwd);
            return true;
        } catch (Exception ex) {
            System.out.println(ex.getMessage());
            return false;
        } finally {
            if (connection != null) {
                connection.close();
            }
        }
    }

    //2.测试AutoCommit=true;
    //此次测试耗时11411ms
    public void BatchByAutoCommit()throws Exception {
        long start = System.currentTimeMillis();
        try{
            connection = DriverManager.getConnection(DB_URL,uid,pwd);
            PreparedStatement ps = null;
            ps=connection.prepareStatement(insertSql);
            Random random = new Random();
            for(int i=0;i<1000000;i++){
                ps.setObject(1,new Integer(random.nextInt(1000000)));
                ps.addBatch();
                //每1000条数据提交一次,防止出现内存溢出的情况;
                if (i % 999 == 0) {
                    ps.executeBatch();
                    ps.clearBatch();
                }
            }
            //最后的一次也需要执行提交
            ps.executeBatch();
            ps.clearBatch();
        }catch (Exception ex) {
            System.out.println(ex.getMessage());
        } finally {
            if (connection != null) {
                connection.close();
            }
        }
        System.out.println("百万条数据插入用时:" + (System.currentTimeMillis() - start)+"【单位:毫秒】");
    }
    //3.测试AutoCommit=false;
    //此次耗时14084ms,根据测试,未发现AutoCommit设置与否对测试插入耗时结果的影响
    public void BatchNoAutoCommit()throws Exception {
        long start = System.currentTimeMillis();
        try{
            connection = DriverManager.getConnection(DB_URL,uid,pwd);
            connection.setAutoCommit(false);
            PreparedStatement ps = null;
            ps=connection.prepareStatement(insertSql);
            Random random = new Random();
            for(int i=0;i<1000000;i++){
                ps.setObject(1,new Integer(random.nextInt(1000000)));
                ps.addBatch();
                //每1000条数据提交一次,防止出现内存溢出的情况;
                if (i % 999 == 0) {
                    ps.executeBatch();
                    ps.clearBatch();
                }
            }
            //最后的一次也需要执行提交
            ps.executeBatch();
            ps.clearBatch();
        }catch (Exception ex) {
            System.out.println(ex.getMessage());
        } finally {
            if (connection != null) {
                connection.close();
            }
        }
        System.out.println("百万条数据插入用时:" + (System.currentTimeMillis() - start)+"【单位:毫秒】");
    }
    //4.测试使用Mybatis批量提交
    //此方法耗时1202058ms合计20分钟(setAutoCommit(true))
    //此方法耗时422900ms合计7分钟(setAutoCommit(false)),速度提升了3倍
    public void BatchByMybatis() throws Exception{
        String resource = "mybatis-config.xml";
        InputStream inputStream = Resources.getResourceAsStream(resource);
        SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
        // 创建SqlSession对象
        SqlSession sqlSession = sqlSessionFactory.openSession();
        sqlSession.getConnection().setAutoCommit(false);
        // 获取UserMapper对象
        IInsertMapper iInsertMapper = sqlSession.getMapper(IInsertMapper.class);
        Random random = new Random();
        long start = System.currentTimeMillis();
        try {
            for (int i = 0; i < 1000000; i++) {
                iInsertMapper.insertBatch(new Integer(random.nextInt(1000000)));
                //每1000条数据提交一次,防止出现内存溢出的情况;
                if (i % 999 == 0) {
                    sqlSession.commit();
                    sqlSession.clearCache();
                }
            }
            sqlSession.commit();
            sqlSession.clearCache();
        }catch (Exception ex){
            sqlSession.rollback();
        }
        finally {
            sqlSession.close();
        }
        System.out.println("百万条数据插入用时:" + (System.currentTimeMillis() - start)+"【单位:毫秒】");
    }
    //5.使用Mybatis实现原生的批量提交
    //此方法耗时14044ms
    public void BatchByMyBatisUseJDBC()throws Exception {

        long start = System.currentTimeMillis();
        try{
            String resource = "mybatis-config.xml";
            InputStream inputStream = Resources.getResourceAsStream(resource);
            SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
            // 创建SqlSession对象
            SqlSession sqlSession = sqlSessionFactory.openSession();
            connection=sqlSession.getConnection();
            connection.setAutoCommit(false);
            PreparedStatement ps = null;
            ps=connection.prepareStatement(insertSql);
            Random random = new Random();
            for(int i=0;i<1000000;i++){
                ps.setObject(1,new Integer(random.nextInt(1000000)));
                ps.addBatch();
                //每1000条数据提交一次,防止出现内存溢出的情况;
                if (i % 999 == 0) {
                    ps.executeBatch();
                    ps.clearBatch();
                }
            }
            //最后的一次也需要执行提交
            ps.executeBatch();
            ps.clearBatch();
            sqlSession.close();
        }catch (Exception ex) {
            System.out.println(ex.getMessage());
        } finally {
            if (connection != null) {
                connection.close();
            }
        }
        System.out.println("百万条数据插入用时:" + (System.currentTimeMillis() - start)+"【单位:毫秒】");
    }
    //6.使用Mybatis实现原生的批量提交多个字段
    //此方法第一次测试耗时27782ms,第二次测试耗时18376ms
    //测试结果得出,字段越多,插入的时间越长,相较于2个字段而言,10个字段的时间时1个字段的2倍
    public void BatchByMyBatisUseJDBCManyField()throws Exception {

        long start = System.currentTimeMillis();
        try{
            String resource = "mybatis-config.xml";
            InputStream inputStream = Resources.getResourceAsStream(resource);
            SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
            // 创建SqlSession对象
            SqlSession sqlSession = sqlSessionFactory.openSession();
            connection=sqlSession.getConnection();
            connection.setAutoCommit(false);
            PreparedStatement ps = null;
            ps=connection.prepareStatement("insert into t_inserttest(field1,field2,field3,field4,field5,field6,field7,field8,field9,field10)value(?,?,?,?,?,?,?,?,?,?)");
            Random random = new Random();
            for(int i=0;i<1000000;i++){
                ps.setObject(1,new Integer(random.nextInt(1000000)));
                ps.setObject(2,new Integer(random.nextInt(1000000)));
                ps.setObject(3,new Integer(random.nextInt(1000000)));
                ps.setObject(4,new Integer(random.nextInt(1000000)));
                ps.setObject(5,new Integer(random.nextInt(1000000)));
                ps.setObject(6,new Integer(random.nextInt(1000000)));
                ps.setObject(7,new Integer(random.nextInt(1000000)));
                ps.setObject(8,new Integer(random.nextInt(1000000)));
                ps.setObject(9,new Integer(random.nextInt(1000000)));
                ps.setObject(10,new Integer(random.nextInt(1000000)));
                ps.addBatch();
                //每1000条数据提交一次,防止出现内存溢出的情况;
                if (i % 999 == 0) {
                    ps.executeBatch();
                    ps.clearBatch();
                }
            }
            //最后的一次也需要执行提交
            ps.executeBatch();
            ps.clearBatch();
            sqlSession.close();
        }catch (Exception ex) {
            System.out.println(ex.getMessage());
        } finally {
            if (connection != null) {
                connection.close();
            }
        }
        System.out.println("百万条数据插入用时:" + (System.currentTimeMillis() - start)+"【单位:毫秒】");
    }
}

  1. 测试类源代码

package com.sc.test;

import com.sc.common.MySqlHelper;
import org.junit.Test;

public class TestMain {
    @Test
    public void testConnection(){
        MySqlHelper msh=new MySqlHelper();
        try {
            if (msh.isConnect()) {
                System.out.println("连接成功!");
            }else{
                System.out.println("连接失败!");
            }
        }catch (Exception ex){
            System.out.println(ex.getMessage());
        }
    }
    @Test
    public void testByAutoCommit(){
        MySqlHelper msh=new MySqlHelper();
        try {
           msh.BatchByAutoCommit();
        }catch (Exception ex){
            System.out.println(ex.getMessage());
        }
    }
    @Test
    public void testNoAutoCommit(){
        MySqlHelper msh=new MySqlHelper();
        try {
            msh.BatchNoAutoCommit();
        }catch (Exception ex){
            System.out.println(ex.getMessage());
        }
    }
    @Test
    public void testMybatis(){
        MySqlHelper msh=new MySqlHelper();
        try {
            msh.BatchByMybatis();
        }catch (Exception ex){
            System.out.println(ex.getMessage());
        }
    }
    @Test
    public void testMyBatisUseJDBC(){
        MySqlHelper msh=new MySqlHelper();
        try {
            msh.BatchByMyBatisUseJDBC();
        }catch (Exception ex){
            System.out.println(ex.getMessage());
        }
    }
    @Test
    public void testMyBatisUserJDBCManyField(){
        MySqlHelper msh=new MySqlHelper();
        try {
            msh.BatchByMyBatisUseJDBCManyField();
        }catch (Exception ex){
            System.out.println(ex.getMessage());
        }
    }
}

  1. 测试结果说明

a)     方法2、3使用JDBC直接实现批量插入,区别在于3中setAutoCommit=false;

根据实际测试情况,两者在插入1000W条数据的时候速度相差不是特别大。

b)    方法4使用Mybatis的批处理方法实现批量插入,分别进行了两种测试,即setAutoCommit=true和false的情况下,两者速度差距达到了3倍,但与直接使用JDBC进行批量插入速度相差依然很大

c)     方法5测试使用Mybatis直接调用JDBC进行批量插入,测试情况显示,与直接使用JDBC的速度差距不大。

d)    方法6测试在插入多个字段与单个字段的情况下两者的速度差距,经过两次测试,第一个10个字段的速度是单个字段速度的2倍;第二次测试速度相差不多,猜测是因为数据库缓存的原因

e)     总体测试过程中,数据库CPU使用率大幅度提升,因为使用1000条数据提交一次的方法,内存使用率有提升,但变化不是特别明显。实际开发过程中不建议大量使用批量插入的方法,避免对数据库造成过大的压力

标签:ps,Java,批量,random,System,插入,connection,ex,new
From: https://www.cnblogs.com/ckym/p/17690381.html

相关文章

  • java 字符串常用API
      importjava.util.Scanner;publicclassMain{publicstaticvoidmain(Stringargs[]){Scannersc=newScanner(System.in);Strings="1233.32";doubley=Double.parseDouble(s);//将一个字符串强制转化为浮点数Stri......
  • JavaSE--多线程
    一、多线程1、进程与线程概念  进程是一个应用程序(1个进程是一个软件),一个进程可以启动多个线程  线程是一个进程中的执行场景/执行单元2、进程与线程的关系  a)进程与线程    进程可以看作是一个公司,线程就是公司中的一个小员工    进程A与进程B的内存独立不......
  • JavaSE--注解
    一、注解1、注解概述  注解,又叫叫做注释类型,Annotation  注解Annotation是一种引用数据类型。编译之后也是生成xxx.class文件。2、语法格式//定义语法格式[修饰符列表]@interface注解类型名{}//使用时语法格式@注解类型名public@interfaceMyAnnotation{......
  • 无涯教程-JavaScript - OCT2HEX函数
    描述OCT2HEX函数将八进制数转换为十六进制。语法OCT2HEX(number,[places])争论Argument描述Required/OptionalNumber您要转换的八进制数。数字不得超过10个八进制字符(30位)。数字的最高有效位是符号位。其余的29位是幅度位。负数使用二进制补码表示。Required......
  • 9.9续8.31java添加图片
    JLabel管理区域:图片,文字API帮助文档:方法的用法宽高(单位:像素),边框 将图片文件夹粘贴到idea当前模块(最大)下 Imagelcon图片对象:ImageIcon对象名=newImageIcon(图片地址);JLabel对象名=newJLabel(图片对象名);  //管理容器的创建add(管理对象名);  //位置确定后再调用......
  • 无涯教程-JavaScript - OCT2DEC函数
    描述OCT2DEC函数将八进制数转换为十进制数。语法OCT2DEC(number)争论Argument描述Required/OptionalNumber您要转换的八进制数。数字不得超过10个八进制字符(30位)。数字的最高有效位是符号位。其余的29位是幅度位。负数使用二进制补码表示。RequiredNotes如......
  • 使用IDEA连接Hive数据库使用Java代码实现增删改查还需要一个Hive配置类
    可以取名为:HiveConfig--packagecom.example.config;importcom.alibaba.druid.pool.DruidDataSource;importlombok.Data;importorg.springframework.beans.factory.annotation.Qualifier;importorg.springframework.boot.context.properties.ConfigurationProperties;i......
  • 无涯教程-JavaScript - OCT2BIN函数
    描述OCT2BIN函数将八进制数转换为二进制数。语法OCT2BIN(number,[places])争论Argument描述Required/OptionalNumber您要转换的八进制数。数字不能超过10个字符。数字的最高有效位是符号位。其余的29位是幅度位。负数使用二进制补码表示。RequiredPlaces要......
  • JavaSE--反射机制
    一、反射机制  java.lang.reflect.*;1、反射机制的作用  通过java语言中的反射机制可以操作字节码文件,可以读和修改字节码文件。  通过反射机制可以操作代码片段(class文件)2、反射机制相关的类  java.lang.Class:代表整个字节码,代表一个类型,代表整个类  java.lang.......
  • 无涯教程-JavaScript - IMTAN函数
    描述IMTAN函数以x+yi或x+yj文本格式返回复数的切线。复数的切线由以下公式计算-tan(z)=正弦(z)/cos(z)语法IMTAN(inumber)争论Argument描述Required/OptionalInumberAcomplexnumberforwhichyouwantthetangent.RequiredNotesExcel中的复数仅存储为......