java - mysql jdbc 即使在 rewriteBatchedStatements = true 之后也不批处理查询

标签 java mysql jdbc spring-boot amazon-rds

我一直在整个互联网 + stackoverflow 上阅读有关为什么 jdbc 批量更新如此缓慢的信息。看起来正确的解决方法是在连接字符串中设置 rewriteBatchedStatements = true。但我似乎无法让它为我工作。

我正在使用 springboot 和 spring-jdbc 我在我的 application.properties 中设置了 rewriteBatchedStatements = true

spring.datasource.url=jdbc:mysql://RDS_URL.us-west-2.rds.amazonaws.com/DATABASE?rewriteBatchedStatements=true

我还设置了一个断点来验证 ?rewriteBatchedStatements=true 是否反射(reflect)在代码中

我将 general_log 设置为 true,在查看日志时我发现插入没有被正确地批处理

这是我的sql字符串的样子

private static String INSERT_USER_TO_GROUP_SQL = "INSERT INTO users (groupId, phoneNumber, accountId, source) VALUES(?, ?, ?, ?)";

日志中的行都是这样的

45 查询 INSERT INTO 用户 (groupId, phoneNumber, accountId, source) VALUES('49', '99999999999', '123', 'web')

我做批量插入的java代码是

executor.submit(() -> {
  jdbcTemplate.batchUpdate(INSERT_USER_TO_GROUP_SQL, new BatchPreparedStatementSetter() {

    @Override
    public void setValues(PreparedStatement ps, int i) throws SQLException {
      Subscriber subscriber = subscribers.get(i);
      ps.setString(1, subscriberGroup.getGroupId());
      ps.setString(2, subscriber.getPhoneNumber());
      ps.setString(3, accountId);
      ps.setString(4, subscriberGroup.getSource());
    }

    @Override
    public int getBatchSize() {
      return subscribers.size();
    }

  }); // end BatchPreparedStatementSetter lambda class
}); // end thread

这是 batchUpdate 方法的一个片段,如下所示,正如您所看到的,它调用了 addBatch(),最后调用了 executeBatch()

for (int i = 0; i < batchSize; i++) {
    pss.setValues(ps, i);
    if (ipss != null && ipss.isBatchExhausted(i)) {
        break;
    }
    ps.addBatch();
}
return ps.executeBatch();

这是我要插入的表格

CREATE TABLE `users` (
  `id` int(11) unsigned NOT NULL AUTO_INCREMENT,
  `phoneNumber` varchar(20) DEFAULT NULL,
  `groupId` varchar(11) DEFAULT NULL,
  `source` varchar(30) DEFAULT NULL,
  `accountId` varchar(50) DEFAULT NULL,
  `deleted` int(1) DEFAULT '0',
  `timestamp` datetime DEFAULT CURRENT_TIMESTAMP,
  PRIMARY KEY (`id`),
  UNIQUE KEY `phoneNumber` (`phoneNumber`,`groupId`,`accountId`)
) ENGINE=InnoDB AUTO_INCREMENT=21677 DEFAULT CHARSET=latin1;

此外,我什至尝试过不依赖 jdbc.batchUpdate() 并自己完成。仍然没有运气

    Connection connection = jdbcTemplate.getDataSource().getConnection();
    connection.setAutoCommit(false);
    PreparedStatement preparedStatement = 
    connection.prepareStatement(INSERT_USER_TO_GROUP_SQL);

    preparedStatement.setString(1, "1");
    preparedStatement.setString(2, "2");
    preparedStatement.setString(3, "3");
    preparedStatement.setString(4, "4");
    preparedStatement.addBatch();

    preparedStatement.setString(1, "11");
    preparedStatement.setString(2, "22");
    preparedStatement.setString(3, "33");
    preparedStatement.setString(4, "44");
    preparedStatement.addBatch();

    preparedStatement.executeBatch();
    connection.commit();

此外,我还试图排除准备好的语句存在的问题,因此我只尝试对查询进行硬编码。仍然没有运气。

Connection connection = jdbcTemplate.getDataSource().getConnection();
Statement statement = connection.createStatement();
statement.addBatch("INSERT INTO users (groupId, phoneNumber, accountId, source) VALUES('1', '2', '3', '4')");
statement.addBatch("INSERT INTO users (groupId, phoneNumber, accountId, source) VALUES('11', '22', '33', '44')");
statement.executeBatch();

这是我pom中jdbc的版本

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-jdbc</artifactId>
    <version>1.5.2.RELEASE</version>
</dependency>

<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-jdbc</artifactId>
    <version>4.3.6.RELEASE</version>
</dependency>

我希望此参数能够加快插入速度,并让日志显示正确批处理的插入语句。大多数 SO 文章显示人们只需在 url 中设置 rewritebatchedstatements = true 就可以了。

最佳答案

对于其他遇到 jdbcTemplate 连接 url 不遵守 rewriteBatchedStatements = true 问题的人,请检查 pom.xml 中的 mysql-connector-java 版本>

在写这个问题的时候我有

<dependency>
        <groupId>mysql</groupId>
        <artifactId>mysql-connector-java</artifactId>
        <version>5.1.9</version>
</dependency>

由于我的批量写入是一个接一个发生的,因此版本 5.1.9 似乎不支持批量更新,并且会退回,如 spring docs 中所述

batchUpdate() -- Will fall back to separate updates on a single Statement if the JDBC driver does not support batch updates.

将此升级到 5.1.18 版后,我得到了正确的批量更新,并在 mysql 通用日志中进行了验证。

也是我遇到的一个错误,它可能会节省其他人一些时间。在 5.1.23 版中,当您配置 db url 以包含 profileSQL=true 时,我想大多数人都会这样做,有一个 bug使用驱动程序和 profileSQL。

关于java - mysql jdbc 即使在 rewriteBatchedStatements = true 之后也不批处理查询,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/44489407/

相关文章:

java - JTable 在 JFrame 的(单独的类)JTextfield 中显示选定的行数据

Java for 线程中的循环

Java 图形 - 在 Jbutton 上绘制形状

mysql - 使用 SQL 查找重复项? - 编写 SQL 语句?

java - 使用 JDBC 连接到 MSSQL 时出现 'unhandled token type: unknown token: 0x53' 错误

java - 错误: Client does not support authentication protocol requested by server; consider upgrading MySQL client

java - 在 Java 中生成 PDF

mysql - 当其他事务失败时,Spring Boot事务停止自动提交或回滚

php - mysql 准备好的语句不起作用

java - JPA:使用类似于 ResultSet 的访问/SQL-JPA 进行动态查询?