【数据库】实现批量快速插入大量数据的六种方案

一、(MySQL)通过函数/存储过程

1、链接

https://www.jb51.net/article/207999.htm

https://blog.csdn.net/FloraCHY/article/details/117792903

2、代码

-- 进入数据库
use test;
-- 显示所有表
show tables;
-- 创建majors表
create table majors(id int, major varchar(255));
-- 定义结束符$
delimiter "$";
-- 创建存储过程,定义存储方法
create procedure batchInsert(in args int)
begin
declare i int default 1;
-- 开启事务(重要!不开的话,100w数据需要论天算)
start transaction;
while i <= args do
insert into majors(id,major) value(i,concat("软件工程-",i));
set i = i+ 1;
end while;
commit;
end
$
 
-- 调用函数,生成数据
-- 先生成10w条试试,同时输入$, 回车执行
call batchInsert(100000);
$

3、性能

10000条数据用了0.9s

100000条,5s执行完

100w条数据用了58s

二、通过jdbc的批量插入语句(add/executeBatch)

1、链接

http://t.zoukankan.com/lizm166-p-7890168.html

2、代码

//获取要设置的Arp基准的List后,插入Arp基准表中    
    public boolean insertArpStandardList(List<ArpTable> list) {
        Connection conn = null;
        PreparedStatement ps = null;
        ResultSet rs = null;
        //MySql的JDBC连接的url中要加rewriteBatchedStatements参数,并保证5.1.13以上版本的驱动,才能实现高性能的批量插入。
        //优化插入性能,用JDBC的addBatch方法,但是注意在连接字符串加上面写的参数。
        //例如: String connectionUrl="jdbc:mysql://192.168.1.100:3306/test?rewriteBatchedStatements=true" ;
        String sql = "insert into arp_standard(guid, devicebrand, devicename, deviceip, ipaddress, " +
                     "macaddress, createtime) values(?,?,?,?,?,?,?)";
        try{
            conn = DBConnection.getConnection();
            ps = conn.prepareStatement(sql);
            //优化插入第一步设置手动提交  
            conn.setAutoCommit(false); 
            int len = list.size();
            for(int i=0; i<len; i++) {
                ps.setString(1, list.get(i).getGuid());
                ps.setString(2, list.get(i).getDeviceBrand());
                ps.setString(3, list.get(i).getDeviceName());
                ps.setString(4, list.get(i).getDeviceIp());
                ps.setString(5, list.get(i).getIpAddress());
                ps.setString(6, list.get(i).getMacAddress());
                ps.setString(7, list.get(i).getCreateTime());
                //if(ps.executeUpdate() != 1) r = false;    优化后,不用传统的插入方法了。
                //优化插入第二步插入代码打包,等一定量后再一起插入。
                ps.addBatch(); 
                //if(ps.executeUpdate() != 1)result = false;
                //每200次提交一次 
                if((i!=0 && i%200==0) || i==len-1){//可以设置不同的大小;如50,100,200,500,1000等等  
                    ps.executeBatch();  
                    //优化插入第三步提交,批量插入数据库中。
                    conn.commit();  
                    ps.clearBatch();//提交后,Batch清空。
                }
            }
        } catch (Exception e) {
            System.out.println("MibTaskPack->getArpInfoList() error:" + e.getMessage());
            return false;   //出错才报false
        } finally {
            DBConnection.closeConection(conn, ps, rs);
        }
        return true;
    }

三、通过多线程执行jdbc过程

1、链接

http://t.zoukankan.com/fangts-p-6813515.html

2、代码

package tenThreadInsert;
 
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.SQLException;
import java.util.Date;
 
public class MyThread extends Thread{
                public void run() {
                     String url = "jdbc:mysql://127.0.0.1/teacher"; 
                     String name = "com.mysql.jdbc.Driver"; 
                     String user = "root"; 
                     String password = "123456"; 
                    Connection conn = null; 
                    try {
                        Class.forName(name);
                        conn = DriverManager.getConnection(url, user, password);//获取连接 
                        conn.setAutoCommit(false);//关闭自动提交,不然conn.commit()运行到这句会报错
                    } catch (ClassNotFoundException e1) {
                        e1.printStackTrace();
                    } catch (SQLException e) {
                        e.printStackTrace();
                    }
                // 开始时间
                Long begin = new Date().getTime();
                // sql前缀
                String prefix = "INSERT INTO test_teacher (t_name,t_password,sex,description,pic_url,school_name,regist_date,remark) VALUES ";
                try {
                    // 保存sql后缀
                    StringBuffer suffix = new StringBuffer();
                    // 设置事务为非自动提交
                    conn.setAutoCommit(false);
                    // 比起st,pst会更好些
                    PreparedStatement  pst = (PreparedStatement) conn.prepareStatement("");//准备执行语句
                    // 外层循环,总提交事务次数
                    for (int i = 1; i <= 10; i++) {
                        suffix = new StringBuffer();
                        // 第j次提交步长
                        for (int j = 1; j <= 100000; j++) {
                            // 构建SQL后缀
                            suffix.append("('" +i*j+"','123456'"+ ",'男'"+",'教师'"+",'www.bbb.com'"+",'Java大学'"+",'"+"2016-08-16 14:43:26"+"','备注'" +"),");
                        }
                        // 构建完整SQL
                        String sql = prefix + suffix.substring(0, suffix.length() - 1);
                        // 添加执行SQL
                        pst.addBatch(sql);
                        // 执行操作
                        pst.executeBatch();
                        // 提交事务
                        conn.commit();
                        // 清空上一次添加的数据
                        suffix = new StringBuffer();
                    }
                    // 头等连接
                    pst.close();
                    conn.close();
                } catch (SQLException e) {
                    e.printStackTrace();
                }
                // 结束时间
                Long end = new Date().getTime();
                // 耗时
                System.out.println("100万条数据插入花费时间 : " + (end - begin) / 1000 + " s"+"  插入完成");
    }  
}
 测试代码

package tenThreadInsert;
 
public class Test {
 
    public static void main(String[] args) {
        for (int i = 1; i <=10; i++) {
              new MyThread().start();
            }
    }
 
}

四、一次性插入多条记录

1、原理

MySQL:

INSERT INTO Persons (LastName, Address) VALUES ('Wilson', 'Champs-Elysees'),('Gates', 'Champs-Elysees')

Oracle:

insert into 表名 (字段1)

select '1' from dual

union all

select '2' from dual

2、代码

(1)调用

public static Boolean insertManyByOne(int num) {
        String sql = GenSqlUtil.genInsManySql(num);
        // System.out.println(sql);
        jdbcUtils.insertMany(sql);
        System.out.println("共插入" + num + "条数据");
        return true;
    }


public static String genInsManySql(int num) {
        String sql = "INSERT INTO TEST.\"ABANK\"\n ";
        for (int i = 0; i < num; i++) {
            sql = sql.concat("select '1', 'CH', '9999', 'Zürcher Kantonalbank', " +
                    "'ZKBKCHZZ80A', ' ', TO_DATE('2009-11-10 00:00:00', 'SYYYY-MM-DD HH24:MI:SS'), " +
                    "TO_DATE('1599-12-31 00:00:00', 'SYYYY-MM-DD HH24:MI:SS'), " +
                    "TO_DATE('2017-07-12 00:00:00', 'SYYYY-MM-DD HH24:MI:SS'), " +
                    "'ADMIN', TO_DATE('1599-12-31 00:00:00', 'SYYYY-MM-DD HH24:MI:SS'), " +
                    "'ADMIN', TO_TIMESTAMP('2021-04-23 08:54:05.000', 'SYYYY-MM-DD HH24:MI:SS:FF3'), " +
                    "TO_TIMESTAMP('"+ dateFormat.format(calendar.getTime()) +
                    "', 'SYYYY-MM-DD HH24:MI:SS:FF3'), " +
                    "HEXTORAW('"+ RandNumGenUtil.genDefLenStr(15) +"') from dual");
            if (i != num -1) {
                sql = sql.concat("\n union all \n");
            }
        }
        return sql;
    }

(2)jdbcutils

package com.boulderaitech.utils;

import java.sql.*;
import java.util.Arrays;

public class JDBCUtil {
    private String user;
    private String pass;
    private String url;

    private Connection conn = null;//连接对象
    private ResultSet rs = null;//结果集对象
    private Statement sm = null;

    /**
     * 构造函数获得数据库用户名和密码
     *
     * @param user
     * @param pass
     */
    public JDBCUtil(String user, String pass) {
        this.user = user;
        this.pass = pass;
        this.url = "jdbc:oracle:thin:@//172.16.5.162:1521/helowin";
    }

    /**
     * 连接数据库
     *
     * @return
     */
    public Connection createConnection() {
        String sDBDriver = "oracle.jdbc.driver.OracleDriver";
        try {
            Class.forName(sDBDriver).newInstance();
            conn = DriverManager.getConnection(url, user, pass);
        } catch (Exception e) {
            System.out.println("数据库连接失败");
            e.printStackTrace();
        }
        return conn;
    }

    /**
     * 关闭数据库
     *
     * @param conn
     */
    public void closeConnection(Connection conn) {
        try {
            if (conn != null) {
                conn.close();
            }
        } catch (Exception e) {
            System.out.println("数据库关闭失败");
            e.printStackTrace();
        }
    }

    /**
     * 插入数据
     *
     * @param insert 插入语句
     * @return
     */
    public int insert(String insert) {
        conn = createConnection();
        //String insert = "insert into t_department values('D004','金融部')";
        int re = 0;
        try {
            conn.setAutoCommit(false);//事物开始

            sm = conn.createStatement();
            re = sm.executeUpdate(insert);
            if (re < 0) {               //插入失败
                conn.rollback();      //回滚
                sm.close();
                closeConnection(conn);
                return re;
            }
            conn.commit();            //插入正常
            sm.close();
            closeConnection(conn);
            return re;
        } catch (Exception e) {
            e.printStackTrace();
        }
        closeConnection(conn);
        return 0;
    }

    /**
     * 批量插入数据
     */
    public int insertBatch(String[] sql) {
        conn = createConnection();
        //String insert = "insert into t_department values('D004','金融部')";
        int re = 0;
        try {
            conn.setAutoCommit(false);//事务开始
            sm = conn.createStatement();
            Arrays.stream(sql).forEach(x->{
                try {
                    sm.executeUpdate(x);
                } catch (SQLException e) {
                    e.printStackTrace();
                }
            });
            conn.commit();            //插入正常
            sm.close();
            closeConnection(conn);
            return re;
        } catch (Exception e) {
            e.printStackTrace();
        }
        closeConnection(conn);
        return 0;
    }

    /**
     * 查询语句
     * 返回结果集
     *
     * @param select
     * @return
     */
    public ResultSet selectSql(String select) {
        conn = createConnection();
        try {
            sm = conn.createStatement();
            rs = sm.executeQuery(select);
            return rs;
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }

    /**
     * 根据结果集输出
     *
     * @param rs
     */
    public void printRs(ResultSet rs) {
        int columnsCount = 0;
        boolean f = false;
        try {
            if (!rs.next()) {
                return;
            }
            ResultSetMetaData rsmd = rs.getMetaData();
            columnsCount = rsmd.getColumnCount();//数据集的列数
            for (int i = 0; i < columnsCount; i++) {
                System.out.print(rsmd.getColumnLabel(i + 1) + "/n"); //输出列名
            }
            System.out.println();

            while (!f) {
                for (int i = 1; i <= columnsCount; i++) {
                    //System.out.print(rs.getString(i)+"/t");
                    //逻辑处理
                    String name = rs.getString("NAME");

                    System.out.print(rs.getString("NAME") + "/n");
                }
                System.out.println();
                if (!rs.next()) {
                    f = true;
                }
            }
            rs.close();
        } catch (Exception e) {
            e.printStackTrace();
        }
        closeConnection(conn);
    }

    /**
     * 插入数据
     *
     * @param update 更新语句
     * @return
     */
    public int update(String update) {
        conn = createConnection();
        //String insert = "insert into t_department values('D004','金融部')";
        int re = 0;
        try {
            conn.setAutoCommit(false);//事物开始

            sm = conn.createStatement();
            re = sm.executeUpdate(update);
            if (re < 0) {               //插入失败
                conn.rollback();      //回滚
                sm.close();
                closeConnection(conn);
                return re;
            }
            conn.commit();            //插入正常
            sm.close();
            closeConnection(conn);
            return re;
        } catch (Exception e) {
            e.printStackTrace();
        }
        closeConnection(conn);
        return 0;
    }

    public int insertMany(String sql) {
        conn = createConnection();
        int re = 0;
        try {
            conn.setAutoCommit(false);//事物开始

            sm = conn.createStatement();
            re = sm.executeUpdate(sql);
            if (re < 0) {               //插入失败
                conn.rollback();      //回滚
                sm.close();
                closeConnection(conn);
                return re;
            }
            conn.commit();            //插入正常
            sm.close();
            closeConnection(conn);
            return re;
        } catch (Exception e) {
            e.printStackTrace();
        }
        closeConnection(conn);
        return 0;
    }
}

五、通过定时器实现定时执行

public static Boolean insertBatchFixTime(int numOfInsert, int timePerEpoch) {
        Timer timer = new Timer();
        timer.schedule(new TimerTask() {
            @Override
            public void run() {
                insertManyByOne(numOfInsert);
            }
        }, 0L, timePerEpoch * 1000L);
        System.out.println("当前线程:" + Thread.currentThread().getName() + " 当前时间" + LocalDateTime.now());
        return true;
    }

六、通过循环实现批量插入

public static Boolean insertBatchFixCircle(int numOfEachInsert, int numOfEpoch) {
        LocalDateTime start = LocalDateTime.now();
        for (int i = 0; i < numOfEpoch; i++) {
            insertManyByOne(numOfEachInsert);
        }
        System.out.println("共插入" + numOfEachInsert * numOfEpoch+"条数据");
        LocalDateTime end = LocalDateTime.now();
        System.out.println("共耗时" + Duration.between(start, end).toMillis() + "ms");
        return true;
    }
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值