我一直在阅读整个互联网+ 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>
并且有效。
答案 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。