JDBC主题

  1. JDBC初出茅庐-建立数据库连接 https://www.7benshu.com/post/2020/03/21-1/
  2. JDBC小试牛刀-数据库操作 https://www.7benshu.com/post/2020/03/21-2/
  3. JDBC略有建树-二进制操作 https://www.7benshu.com/post/2020/03/21-3/
  4. JDBC出类拔萃-数据库批量操作 https://www.7benshu.com/post/2020/03/21-4/
  5. JDBC百里挑一|数据库事务 https://www.7benshu.com/post/2020/03/22-1/
  6. JDBC卓越超群-DAO https://www.7benshu.com/post/2020/03/22-2/
  7. JDBC独步江湖-数据库连接池 https://www.7benshu.com/post/2020/04/9-1/

介绍

在对关系型数据库做大量数据输入的时候, 不仅仅需要数据库有吃的能力, 程序还要有插入的能力, 下面有几个方式, 大家可以体验下, 自己测试测试, 话不多说, 效果非常的明显

批量执行SQL语句

当需要成批插入或者更新记录时,可以采用Java的批量更新机制,这一机制允许多条语句一次性提交给数据库批量处理。通常情况下比单独提交处理更有效率

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

  • addBatch(String):添加需要批量处理的SQL语句或是参数;
  • executeBatch():执行批量处理语句;
  • clearBatch():清空缓存的数据

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

  • 多条SQL语句的批量处理;
  • 一个SQL语句的批量传参;

高效的批量插入

举例:向数据表中插入30000条数据

  • 数据库中提供一个customers表。创建如下:
1
2
3
4
CREATE TABLE customers(
id INT PRIMARY KEY AUTO_INCREMENT,
NAME VARCHAR(20)
);

方式一:使用Statement

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
Connection conn = JDBCUtils.getConnection();
Statement st = conn.createStatement();

final Stopwatch started = Stopwatch.createStarted();

for (int i = 1; i <= 30000; i++) {
  String sql = String.format("insert into customers(name) values('name_%d')", i);
  st.executeUpdate(sql);
}

started.stop();
JDBCUtils.closeResource(conn, st);
System.out.println("耗时:"+started.elapsed().toMillis());

耗时:8880

方式二:使用PreparedStatement

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
final Stopwatch started = Stopwatch.createStarted();

Connection conn = JDBCUtils.getConnection();
String sql = "insert into customers(name)values(?)";
PreparedStatement ps = conn.prepareStatement(sql);
for (int i = 1; i <= 30000; i++) {
  ps.setString(1, "name_" + i);
  ps.executeUpdate();
}
started.stop();
JDBCUtils.closeResource(conn, ps);
System.out.println("耗时:" + started.elapsed().toMillis());

耗时:8690

方式三

注意: JDBC驱动版本需要5.1.13或以上,才可以使用批处理

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
/*
 * 修改1: 使用 addBatch() / executeBatch() / clearBatch()
 * 修改2:mysql服务器默认是关闭批处理的,我们需要通过一个参数,让mysql开启批处理的支持。
 * 		 ?rewriteBatchedStatements=true 写在配置文件的url后面
 * 修改3:确认驱动版本,一定要注意版本
         <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>5.1.18</version>
        </dependency>
 * 
 */
final Stopwatch started = Stopwatch.createStarted();

Connection conn = JDBCUtils.getConnection();
String sql = "insert into customers(name)values(?)";
PreparedStatement ps = conn.prepareStatement(sql);
for (int i = 1; i <= 30000; i++) {
  ps.setString(1, "name_" + i);

  //1.加入批次
  ps.addBatch();
  if (i % 500 == 0) {
    //2.执行
    ps.executeBatch();
    //3.清空
    ps.clearBatch();
  }
}
started.stop();
JDBCUtils.closeResource(conn, ps);
System.out.println("耗时:" + started.elapsed().toMillis());


耗时:995

方式四

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
final Stopwatch started = Stopwatch.createStarted();

Connection conn = JDBCUtils.getConnection();

//1.设置为不自动提交数据
conn.setAutoCommit(false);

String sql = "insert into customers(name)values(?)";
PreparedStatement ps = conn.prepareStatement(sql);

for (int i = 1; i <= 1000000; i++) {
  ps.setString(1, "name_" + i);

  //1.加入批次
  ps.addBatch();

  if (i % 500 == 0) {
    //2.执行
    ps.executeBatch();
    //3.清空
    ps.clearBatch();
  }
}

//2.提交数据
conn.commit();
started.stop();

JDBCUtils.closeResource(conn, ps);
System.out.println("耗时:" + started.elapsed().toMillis());

耗时:829

总结

以上的测试的耗时, 每次都会结果不一样, 这个跟大家的电脑性能有关系, 看个趋势就好了

数据库的输入的效率直接影响到业务的体验和验证, 提高的方式有很多, 架构也会不一样, 多一个思路, 多一条路