【发布时间】:2020-03-27 21:37:55
【问题描述】:
我有一个烦人的问题,我不知道为什么会这样。简单介绍一下,我在 Spring Boot 项目中使用 MySql 和 JDBC 模板实现了批处理(批量插入)。
所以基本上批量插入工作正常,性能非常惊人,但是有一个小问题真的很烦人,当我插入一个在两列上具有唯一键的表时,它会导致约束异常( id,值)。
所以我有这个代码:
private String INSERT_SQL_PARAMS = "INSERT INTO item_params(p_key, p_value, item_id) values (?,?,?)"
override fun saveParams(configParams: Set<ItemParam>) {
jdbcTemplate!!.update { connection ->
connection.autoCommit = false
val ps: PreparedStatement = connection.prepareStatement(INSERT_SQL_PARAMS)
configParams.forEachIndexed { index, it ->
ps.setLong(1, it.configurationId)
ps.setString(2, it.pKey)
ps.setString(3, it.pValue)
ps.addBatch()
if (index != 0 && index % 1000 == 0) {
ps.executeBatch()
connection.commit()
}
}
ps.executeBatch()
connection.commit()
ps
}
}
当我在 Spring Boot 中使用数据源代理查看日志时,我可以看到实际执行的查询。
所以当我想一次插入例如 2 个项目时,我会在日志中看到:
Batch: True, INSERT INTO item_param(item_id, p_key, p_value) values (1, 1, 1), (2, 2, 2)
Batch: False, INSERT INTO item_param(item_id, p_key, p_value) values ()
所以你可以看到我总是在最后看到一个没有任何值的额外/备用语句,并且由于某种原因日志说 Batch = False。
谁能看到我的代码中缺少的东西,为什么会发生这种情况以及我能用它做什么?
我还有一个问题,例如,如果我有 1000 条记录,我将执行 2 次批处理,一次在 if 语句中,一次在最后。有什么方法可以让我说 ps.executeBatch 只有在查询中有参数的情况下?
【问题讨论】:
-
您的代码在恰好插入 1000/2000/3000/... 项时有一个小错误。
ps.executeBatch()将在循环内运行一次,然后在循环外再次以空批处理运行。你在调试的是这种情况吗? -
我实际上怀疑这一点,我通过插入 3 个项目对此进行了测试,因此它永远不会进入该 if 语句。但是我再次有额外的插入调用......我实际上用这种情况更新了问题,你有没有建议我只有在查询中有一些参数时才能执行查询?
-
保留一个额外的布尔值,在
addBatch时将其设置为 true,在executeBatch时将其设置为 false ? -
附注 - 如果您的应用程序的插入量很大并且批处理速度不够快,您应该尝试批量插入 CSV。它比批处理快得多。
-
感谢您的建议,是的,这应该可以在添加批次时保持布尔值!是的,我知道使用 CSV 的“技巧”,但是批量应该没问题,它不像我会处理数百万个插入。
标签: hibernate spring-boot jdbc spring-jdbc jdbctemplate