Java 之 JDBC:(五)批量插入

一、批量执行 SQL 语句

  1、当需要成批插入或者更新记录时,可以采用 Java 的批量更新机制,这一机制允许多条语句一次性提交给数据库批量处理。

  2、使用 PreparedStatement 可以实现批量数据的操作。

  3、update、delete 本身就具有批量操作的效果。此时的批量操作,主要指的是批量插入,使用 PreparedStatement 实现高效的批量插入操作。

  4、JDBC 的批量处理语句包括下面三个方法:

addBatch(String):添加需要批量处理的SQL语句或是参数;

executeBatch():执行批量处理语句;

clearBatch():清空缓存的数据

    通常我们会遇到两种批量执行 SQL 语句的情况:

    ① 多条 SQL 语句的批量处理;

    ② 一个 SQL 语句的批量传参;

二、高效的批量插入

  1、举例:向数据表中插入 20000 条数据

    数据库中提供一个 goods 表,创建如下:

create table goods (
  id int primary key auto_increment,
  name varchar(20)    
);

  

  2、实现层次一:使用 Statement

    代码实现:

1 Connection conn = JDBCUtils.getConnection();
2 Statement st = conn.createStatement();
3 for(int i = 1;i <= 20000;i++){
4     String sql = "insert into goods(name) values('name_' + "+ i +")";
5     st.executeUpdate(sql);
6 }

  3、实现层次二:使用 PreparedStatement

    代码实现:

 1     @Test
 2     public void testInsert2() {
 3         Connection conn = null;
 4         PreparedStatement ps = null;
 5         try {
 6             
 7             long start = System.currentTimeMillis();
 8             
 9             conn = JDBCUtils.getConnection();
10             String sql = "insert into goods(name)values(?)";
11             ps = conn.prepareStatement(sql);
12             for(int i = 1;i <= 20000;i++){
13                 ps.setObject(1, "name_" + i);
14                 
15                 ps.execute();
16             }
17             
18             long end = System.currentTimeMillis();
19             
20             System.out.println("花费的时间为:" + (end - start));//20000:83065
21         } catch (Exception e) {
22             e.printStackTrace();
23         }finally{
24             JDBCUtils.closeResource(conn, ps);
25         }
26     }

    使用 PreparedStatement 可以进行预编译语句的执行,在数据库服务端会把编译器编译后的语句缓存下来,那么下次调用时只有相同的预编译语句一样就不需再编译了,直接将参数传入语句中就会执行,效率得到了提升。

  4、实现层次三:使用Batch

    修改1:需要使用 addBatch() / executeBatch() / clearBatch() 的API;

    修改2:MySQL 服务器默认是关闭批处理的,我们需要通过一个参数,让MySQL开启批处理的支持。

?rewriteBatchedStatements=true 写在配置文件的url后面

例如:url=jdbc:mysql://localhost:3306/test?rewriteBatchedStatements=true

  

    修改3:使用更新的 MySQL 驱动,驱动:mysql-connector-java-5.1.37-bin.jar

    代码实现:

 1     @Test
 2     public void testInsert3() {
 3         Connection conn = null;
 4         PreparedStatement ps = null;
 5         try {
 6             
 7             long start = System.currentTimeMillis();
 8             
 9             conn = JDBCUtils.getConnection();
10             String sql = "insert into goods(name)values(?)";
11             ps = conn.prepareStatement(sql);
12             for(int i = 1;i <= 1000000;i++){
13                 ps.setObject(1, "name_" + i);
14                 
15                 //1."攒"sql
16                 ps.addBatch();
17                 
18                 if(i % 500 == 0){
19                     //2.执行batch
20                     ps.executeBatch();
21                     
22                     //3.清空batch
23                     ps.clearBatch();
24                 }
25                 
26             }
27             
28             long end = System.currentTimeMillis();
29             
30             System.out.println("花费的时间为:" + (end - start));//20000:83065 -- 565
31         } catch (Exception e) {                                //1000000:16086
32             e.printStackTrace();
33         }finally{
34             JDBCUtils.closeResource(conn, ps);
35             
36         }
37         
38     }

    通过Batch批处理的方式,可以先把SQL“收集”起来,等积攒到一定的条数,然后再让数据库执行,这样一来就可以有效的减少与数据库的交互操作(减少IO),再次对效率的提高。

  5、实现层次四:设置连接不允许自动提交数据

    上面的 Batch 操作,效率来说已经不错了,但是还可以进一步优化:

 1     @Test
 2     public void testInsert4() {
 3         Connection conn = null;
 4         PreparedStatement ps = null;
 5         try {
 6             
 7             long start = System.currentTimeMillis();
 8             
 9             conn = JDBCUtils.getConnection();
10             
11             //设置不允许自动提交数据
12             conn.setAutoCommit(false);
13             
14             String sql = "insert into goods(name)values(?)";
15             ps = conn.prepareStatement(sql);
16             for(int i = 1;i <= 1000000;i++){
17                 ps.setObject(1, "name_" + i);
18                 
19                 //1."攒"sql
20                 ps.addBatch();
21                 
22                 if(i % 500 == 0){
23                     //2.执行batch
24                     ps.executeBatch();
25                     
26                     //3.清空batch
27                     ps.clearBatch();
28                 }
29                 
30             }
31             
32             //提交数据
33             conn.commit();
34             
35             long end = System.currentTimeMillis();
36             
37             System.out.println("花费的时间为:" + (end - start));//20000:83065 -- 565
38         } catch (Exception e) {                                //1000000:16086 -- 5114
39             e.printStackTrace();
40         }finally{
41             JDBCUtils.closeResource(conn, ps);
42         }
43     }

    当把自动提交事务关闭后,会把所有的 SQL 都执行完毕之后再进行事务的提交,相当于上面的执行一部分就进行提交,效率也有所提高(可能并不是很明显)。

 

原文地址:https://www.cnblogs.com/niujifei/p/15013077.html