如果直接使用循环进行批量插入数据,那么只能每次循环时就填充占位符,然后进行插入操作,这让插入1000000万的数据十分低效。
下面代码只演示了这样插入20000行数据就需要30多秒了。
package com.batchinsert;
import com.utils.JDBCUtils;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.SQLException;
/**
* @author 承夕
* @date 2020/3/1 0001 - 20:40
* @contact:https://github.com/chengxi0
*/
public class InsertBatchDeom1 {
public static void main(String[] args) {
String sql = "insert into goods (name) values (?) ;" ;
Connection conn = null ;
PreparedStatement pstm = null;
try {
//获取连接
conn = JDBCUtils.getConnection();
//获取PreparedStatement
pstm = conn.prepareStatement(sql);
long start = System.currentTimeMillis();
for (int i = 1; i <= 20000; i++) {
//填充占位符
pstm.setObject(1, "name_" + i);
pstm.executeUpdate() ;
}
long end = System.currentTimeMillis();
System.out.println(end-start);
//33611 这是用时的毫秒值
} catch (SQLException e) {
e.printStackTrace();
}finally{
JDBCUtils.closeResource(conn, pstm, null);
}
}
}
第一次优化:
类比于IO操作里面的read()方法和read(byte[])方法,前者类似于前面的每次填充占位符然后插入操作,那么,能否一次攒够这么多插入操作,再在数据库中进行一次性插入呢??因此需要使用到三个方法:addBatch() executeBatch() clearBatch()
前提:
默认情况下,Mysql中是关闭批处理的,因此需要在配置文件中添加上属性:rewriteBatchedStatements=true
url=jdbc:mysql://localhost:3306/test?&rewriteBatchedStatements=true
使用更新的MySQL驱动 :mysql-connector-java-5.1.37-bin.jar
package com.batchinsert;
import com.utils.JDBCUtils;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.SQLException;
/**
* @author 承夕
* @date 2020/3/1 0001 - 20:40
* @contact:https://github.com/chengxi0
*/
public class InsertBatchDeom2 {
public static void main(String[] args) {
String sql = "insert into goods (name) values (?) " ;
Connection conn = null ;
PreparedStatement pstm = null;
try {
//获取连接
conn = JDBCUtils.getConnection();
//获取PreparedStatement
pstm = conn.prepareStatement(sql);
long start = System.currentTimeMillis();
for (int i = 1; i <= 1000000; i++) {
//填充占位符
pstm.setObject(1, "name_" + i);
//攒‘sql’
pstm.addBatch();
if (i % 500 == 0) {
//批量执行
pstm.executeBatch();
//清理攒到的sql
pstm.clearBatch();
}
}
long end = System.currentTimeMillis();
System.out.println(end-start);
//9249 这是1000000数据用时的毫秒值
} catch (SQLException e) {
e.printStackTrace();
}finally{
JDBCUtils.closeResource(conn, pstm, null);
}
}
}
此时已经可以在处理1000000数据只是10秒钟不到的时间,那么是否还可以继续优化呢??
第二次优化:
默认情况下,在每次执行操作之后会进行连接提交的,在这里需要不少时间。可以设置在执行完1000000的数据插入操作再进行提交。
conn.setAutoCommit(false);
package com.batchinsert;
import com.utils.JDBCUtils;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.SQLException;
/**
* @author 承夕
* @date 2020/3/1 0001 - 20:40
* @contact:https://github.com/chengxi0
*/
public class InsertBatchDeom3 {
public static void main(String[] args) {
String sql = "insert into goods (name) values (?) " ;
Connection conn = null ;
PreparedStatement pstm = null;
try {
//获取连接
conn = JDBCUtils.getConnection();
//我们在获取连接的时候设置不自动进行提交
conn.setAutoCommit(false);
//获取PreparedStatement
pstm = conn.prepareStatement(sql);
long start = System.currentTimeMillis();
for (int i = 1; i <= 1000000; i++) {
//填充占位符
pstm.setObject(1, "name_" + i);
//攒‘sql’
pstm.addBatch();
if (i % 500 == 0) {
//批量执行
pstm.executeBatch();
//清理攒到的sql
pstm.clearBatch();
}
}
long end = System.currentTimeMillis();
System.out.println(end-start);
//5413 这是1000000数据用时的毫秒值
//插入完再提交咯
conn.commit();
} catch (SQLException e) {
e.printStackTrace();
}finally{
JDBCUtils.closeResource(conn, pstm, null);
}
}
}
这里需要的时间仅仅5秒多一点。