zoukankan      html  css  js  c++  java
  • 第一周:JDBC中批量插入数据问题

    在向数据库中添加数据时,难免会遇到批量添加数据的问题。下面就是使用JDBC来实现批量插入的几种方法。

    准备工作:

    • 在MySQL5数据库中创建一个names
    • 表中就两个字段
      • id:主键,自增
      • name:varchar(25),保证长度够用就行
    CREATE TABLE names(
    	id INT PRIMARY KEY AUTO_INCREMENT,
    	name VARCHAR(25)
    );
    

    方法一:

    最直接的频繁执行SQL语句来插入

    long start = System.currentTimeMillis();
    
    // 获取数据库连接 
    Connection conn= DriverManager.getConnection(url, user, password);
    // SQL语句
    String sql = "insert into names(name) values(?);";
    // 预编译SQL语句
    PreparedStatement ps = conn.prepareStatement(sql);
    
    // 批量插入 2万 条数据
    for (int i = 0; i < 20000; i++) {
        ps.setObject(1, "name_"+i); // 填充占位符?
        ps.execute(); // 每一条数据都执行一次
    }
    
    long end = System.currentTimeMillis();
    
    System.out.println("花费的时间为:" + (end - start)); // 花费的时间为:794551
    
    // 关闭资源
    ps.close();
    conn.close();
    

    方式二:

    使用executeBatch()来批量插入数据

    需要在数据库连接的url中添加rewriteBatchedStatements=true字段,让数据库开启批处理默认

    long start = System.currentTimeMillis();
    
    // 获取数据库连接 
    Connection conn= DriverManager.getConnection(url, user, password);
    // SQL语句
    String sql = "insert into names(name) values(?)"; // 注意这里! 一定不要加结尾的分号;
    // 预编译SQL语句
    PreparedStatement ps = conn.prepareStatement(sql);
    
    // 批量插入 100万 条数据
    for (int i = 1; i <= 1000000; i++) {
        ps.setObject(1, "name_"+i);
    
        // 添加到同一batch中
        ps.addBatch();
    
        if (i % 500 == 0) { // 每批次够500条才执行 控制这个数也可以提高点速度
            // 执行该batch的插入操作
            ps.executeBatch();
    
            // 清空已执行的batch
            ps.clearBatch();
        }
    }
    
    long end = System.currentTimeMillis();
    
    System.out.println("花费的时间为:" + (end - start)); // 花费的时间为:5177
    
    // 关闭资源
    ps.close();
    conn.close();
    

    注意:一定不要给SQL语句添加结尾的;。否则会抛异常。

    java.sql.BatchUpdateException: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near '('name_2'),('name_3'),('name_4'),('name_5'),('name_6'),('name_7'),('name_8'),('n' at line 1...
    

    至于原因,JDBC的源码实在太晦涩了,看一会就前后连接不上了,所以笔者认为应该是由于在MySQL中批量插入的SQL语句的问题。

    就是对于names表,直接在MySQL中用SQL语句来批量添加数据时,可以这样

    insert into names(`name`) values("name_1"), ("name_2"), ("name_3");
    

    这行去掉;也能正常运行

    但是如果这样,注意分号

    insert into names(`name`) values("name_1");, ("name_2"), ("name_3")
    

    那么"name_1"插入表中,后面2和3没有,并且MySQL抛异常。

    ​ 那么或许在JDBC中,每次addBatch(),都是将要放在占位符?的数据先存在ArrayList中,当执行executeBatch()时,遍历ArrayList将第一个数据"name_1"放在SQL语句的?处,后续的全部构造成,("name_2"),("name_3")的形式连接在这条SQL语句后面,最终构造成一个长的插入SQL语句,再执行,完成批量插入。

    即:

    insert into names(`name`) values("name_1")
    insert into names(`name`) values("name_1"), ("name_2")
    insert into names(`name`) values("name_1"), ("name_2"), ("name_3")
    insert into names(`name`) values("name_1"), ("name_2"), ("name_3")..., ("name_batchSize")
    

    这样由于执行拼在一起的SQL就可以完成批量插入。

    但是如果insert into names(name) values(?);结尾有个;,就变成这样:

    insert into names(`name`) values("name_1");
    insert into names(`name`) values("name_1");, ("name_2")
    insert into names(`name`) values("name_1");, ("name_2"), ("name_3")
    insert into names(`name`) values("name_1");, ("name_2"), ("name_3")..., ("name_batchSize")
    

    那么JDBC的对SQL语句的语法检查语义检查无法通过,就会抛异常。

    数据库中也不会有"name_1"这条数据。

    以上是笔者的推测,并没有通过JDBC源码验证。

    方式三:

    在方式二的基础上再进一步优化,除了改变一批次的容量(上面是500)外,还可以设置不允许自动提交数据,改为手动提交数据。

    // 设置不允许自动提交数据
    conn.setAutoCommit(false); // 该行代码放在获取数据库连接后
    
    // ... 批量插入操作同上
    
    // 提交数据
    conn.commit(); // 在批量插入的for循环后
    
    // 花费时间为:3954
    

    另外,还有个executeLargeBatch()方法

    当要总共要插入1亿条数据,并且一个batch为100万

    executeBatch()花费了413635毫秒

    executeLargeBatch()花费了386389毫秒

    emmm...可能不是单纯替换着用的,哈哈哈!

  • 相关阅读:
    深入理解Linux系统调用:write/writev
    MySQL基础语法
    Ubuntu20.04安装MySQL8.0
    关系数据库(事务:一致性+隔离级别)
    基于mykernel 2.0编写一个操作系统内核
    信息安全 学习笔记(1)——常用攻击、网络命令、ARP安全、IP安全
    AI画风迁移——Style Change
    百度算法题回忆
    Java机试--输入输出
    【竞赛项目】阿里天池数据挖掘比赛——快来一起挖掘幸福感
  • 原文地址:https://www.cnblogs.com/jiyou/p/13941255.html
Copyright © 2011-2022 走看看