在Java项目中可能会出现大量向数据库中插入的情况,下面有四种方式实现批量插入,四种方式效率由低到高、循序渐进。
下面使用idea+Mysql8。
向goods表中插入20000条数据
创建表:
CREATE TABLE goods(
id INT PRIMARY KEY AUTO_INCREMENT,
NAME VARCHAR(25)
);
封装连接数据库的基础信息如:用户名、密码等
user=root
password=ad
url=jdbc:mysql://localhost:3306/jdbc?useUnicode=true&characterEncoding=utf8&useSSL=false&serverTimezone=GMT
driverClass=com.mysql.cj.jdbc.Driver
封装数据库连接、关闭方法
package util;
import java.io.InputStream;
import java.sql.*;
import java.util.Properties;
/**封装数据库连接和关闭*/
public class JDBCUtils {
public static Connection getConnection() throws Exception{
//读取配置文件基本信息
InputStream is = ClassLoader.getSystemClassLoader().getResourceAsStream("jdbc.properties");
Properties pros = new Properties();
pros.load(is);
String user = pros.getProperty("user");
String password = pros.getProperty("password");
String url = pros.getProperty("url");
String driverClass = pros.getProperty("driverClass");
//加载驱动
Class.forName(driverClass);
//获取连接
Connection conn = DriverManager.getConnection(url,user,password);
return conn;
}
public static void closeResource(Connection conn, Statement ps){
try {
if(ps != null)
ps.close();
}catch (SQLException e){
e.printStackTrace();
}
try {
if(conn != null)
conn.close();
}catch (SQLException e){
e.printStackTrace();
}
}
public static void closeResource(Connection conn, Statement ps, ResultSet rs){
try {
if(ps != null)
ps.close();
}catch (SQLException e){
e.printStackTrace();
}
try {
if(conn != null)
conn.close();
}catch (SQLException e){
e.printStackTrace();
}
try {
if(rs!=null)
rs.close();
}catch (SQLException e){
e.printStackTrace();
}
}
}
一般不会使用此方式;
此方式会执行多次sql语句,效率低下。
Connection conn = JDBCUtils.getConnection();
Statement st = conn.createStatement();
for(int i = 1;i<=20000;i++){
String sql = "insert into goods(name) values('name_"+i+"')";
st.execute(sql);
}
此方式比上个方式的好处:sql语句在循环外,只执行一次。
public static void testInsert1(){
Connection conn = null;
PreparedStatement ps = null;
try {
long start = System.currentTimeMillis();//计算花费时间
conn = JDBCUtils.getConnection();
String sql = "insert into goods(name) values(?)";
ps = conn.prepareStatement(sql);
for(int i = 1;i<=20000;i++){
ps.setObject(1,"name_"+i);
ps.execute();
}
long end = System.currentTimeMillis();
System.out.println(end-start+"s");
}catch (Exception e){
e.printStackTrace();
}finally {
JDBCUtils.closeResource(conn,ps);
}
}
先将sql“攒”够一定数量,再执行一次,最后清空batch。
三种方法:addBatch()、executeBatch()、clearBatch();
1、mysql服务器默认关闭批处理,需要开启,前面配置文件url中已经开启。
2、需要更新驱动:https://dev.mysql.com/downloads/file/?id=477058
将以上jar驱动文件添加到项目下的lib文件下,并添加为库。
public static void testInsert2(){
Connection conn = null;
PreparedStatement ps = null;
try {
long start = System.currentTimeMillis();//计算花费时间
conn = JDBCUtils.getConnection();
String sql = "insert into goods(name) values(?)";
ps = conn.prepareStatement(sql);
for(int i = 1;i<=20000;i++){
ps.setObject(1,"name_"+i);
//1、“攒”sql
ps.addBatch();
if(i%500 == 0){
//2、执行batch
ps.executeBatch();
//3、清空batch
ps.clearBatch();
}
}
long end = System.currentTimeMillis();
System.out.println(end-start+"ms");
}catch (Exception e){
e.printStackTrace();
}finally {
JDBCUtils.closeResource(conn,ps);
}
}
在上一个方式基础上再设置不允许自动提交数据,等全部完成后,一次性向数据库提交。
setAutoCommit(false);
commit()。
public static void testInsert3(){
Connection conn = null;
PreparedStatement ps = null;
try {
long start = System.currentTimeMillis();//计算花费时间
conn = JDBCUtils.getConnection();
conn.setAutoCommit(false);//不允许自动提交数据
String sql = "insert into goods(name) values(?)";
ps = conn.prepareStatement(sql);
for(int i = 1;i<=20000;i++){
ps.setObject(1,"name_"+i);
//1、“攒”sql
ps.addBatch();
if(i%500 == 0){
//2、执行batch
ps.executeBatch();
//3、清空batch
ps.clearBatch();
}
}
//提交数据
conn.commit();
long end = System.currentTimeMillis();
System.out.println(end-start+"ms");
}catch (Exception e){
e.printStackTrace();
}finally {
JDBCUtils.closeResource(conn,ps);
}
}
最后一种方式比前面的效率提升几倍,甚至几十倍、几百倍。