【数据库】实现批量快速插入大量数据的六种方案
作者:互联网
一、(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;
}
标签:return,String,批量,六种,数据库,int,sql,public,conn 来源: https://www.cnblogs.com/liujinhui/p/16694380.html