即使在rewriteBatchedStatements = true之后,mysql jdbc也没有批处理查询

时间:2017-06-11 22:42:31

标签: java mysql jdbc spring-boot amazon-rds

我一直在阅读整个互联网+ stackoverflow上为什么jdbc批量更新太慢了。看起来正确的解决方法是在连接字符串中设置var (v1, .., vn) = tuple。但我似乎无法让它为我工作。

我正在使用springboot和spring-jdbc 我在我的application.properties

中设置了rewriteBatchedStatements = true
rewriteBatchedStatements = true

我还设置了一个断点来验证spring.datasource.url=jdbc:mysql://RDS_URL.us-west-2.rds.amazonaws.com/DATABASE?rewriteBatchedStatements=true 是否反映在代码中

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

这是我的sql字符串看起来像

?rewriteBatchedStatements=true

日志中的行看起来都是这样的

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

我执行批量插入的java代码是

45 Query   INSERT INTO users (groupId, phoneNumber, accountId, source) VALUES('49', '99999999999', '123', 'web')

以下是方法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 的一个片段,如下所示,您可以看到它调用addBatch(),最后调用executeBatch()

batchUpdate

这是我要插入的表格

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

我甚至尝试过不依赖于jdbc.batchUpdate()并自己动手。仍然没有运气

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;

另外,我试图排除预处理语句的问题,所以我尝试了硬编码查询。仍然没有运气。

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

这是我的pom中的jdbc版本

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

我希望此参数可以加快插入速度,并使日志显示正确批处理的插入语句。大多数SO文章都会向人们展示在网址中设置<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> 并且有效。

1 个答案:

答案 0 :(得分:2)

对于遇到jdbcTemplate连接问题的其他人而言,不尊重rewriteBatchedStatements = true检查mysql-connector-java

中的pom.xml版本

在撰写此问题时,我有

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

由于我的批量写入逐一发生,因此版本5.1.9似乎不支持批量更新,并且如spring docs

中所述回退
  

batchUpdate() - 如果JDBC驱动程序不支持批量更新,将回退到单个Statement的单独更新。

将其转换为版本5.1.18给了我正确的批量更新,在mysql通用日志中验证。

也是我遇到的一个错误,可能会节省一些时间。在版本5.1.23中,当您将db url配置为包含我最想做的profileSQL=true时,有一个bug包含驱动程序和profileSQL。