在Java项目中可能会出现大量向数据库中插入的情况,下面有四种方式实现批量插入,四种方式效率由低到高、循序渐进。

下面使用idea+Mysql8。


题目

向goods表中插入20000条数据
创建表:
CREATE TABLE goods(
id INT PRIMARY KEY AUTO_INCREMENT,
NAME VARCHAR(25)
);

前提

创建jdbc.properties配置文件

封装连接数据库的基础信息如:用户名、密码等

user=root
password=ad
url=jdbc:mysql://localhost:3306/jdbc?useUnicode=true&characterEncoding=utf8&useSSL=false&serverTimezone=GMT
driverClass=com.mysql.cj.jdbc.Driver

创建util软件包,包下创建JDBCUtils类

封装数据库连接、关闭方法

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();
        }
    }
}

 

一、方式一:使用Statement

一般不会使用此方式;

此方式会执行多次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);
}

二、方式二:使用PreparedStatement

此方式比上个方式的好处: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);
        }
    }

三、方式三:Batch

先将sql“攒”够一定数量,再执行一次,最后清空batch。

三种方法:addBatch()、executeBatch()、clearBatch();

Batch前置

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);
        }
    }

最后一种方式比前面的效率提升几倍,甚至几十倍、几百倍。

Logo

华为云1024程序员节送福利,参与活动赢单人4000元礼包,更有热门技术干货免费学习

更多推荐