我正在使用Postgres 9.3,Spring和Java。
来自javadoc的BatchUpdateException:
批量更新中的命令无法正常执行并且抛出
BatchUpdateException
后,驱动程序可能会也可能不会继续处理批处理中的其余命令。如果驱动程序在发生故障后继续处理,则方法BatchUpdateException.getUpdateCounts
返回的数组将为批处理中的每个命令提供一个元素,而不是仅包含在错误之前成功执行的命令的元素。在驱动程序继续处理命令的情况下,任何失败命令的数组元素为Statement.EXECUTE_FAILED
。
我在jdbcTemplate
中注册了翻译器public class DuplicateRecordSQLErrorCodesTranslator extends SQLErrorCodeSQLExceptionTranslator {
@Override
protected DataAccessException doTranslate(String task, String sql, SQLException ex) {
String errorCode = ex.getErrorCode() == 0 ? ex.getSQLState() : String.valueOf(ex.getErrorCode());
if (ex instanceof BatchUpdateException) {
int[] updatesCount = ((BatchUpdateException) ex).getUpdateCounts();
然后在场景中我试图将批量插入100个条目的DB,但其中50个是重复的。最终,我无法在第一个事务中检索所有重复的条目,因为返回的updateCounts
始终为1。
答案 0 :(得分:1)
目前尚不清楚你想要什么。 PostgreSQL Documentation显示了如何编写执行更新或插入的PL / pgSQL函数的示例,具体取决于主键是否已存在。
CREATE TABLE db (a INT PRIMARY KEY, b TEXT);
CREATE FUNCTION merge_db(key INT, data TEXT) RETURNS VOID AS
$$
BEGIN
LOOP
-- first try to update the key
UPDATE db SET b = data WHERE a = key;
IF found THEN
RETURN;
END IF;
-- not there, so try to insert the key
-- if someone else inserts the same key concurrently,
-- we could get a unique-key failure
BEGIN
INSERT INTO db(a,b) VALUES (key, data);
RETURN;
EXCEPTION WHEN unique_violation THEN
-- Do nothing, and loop to try the UPDATE again.
END;
END LOOP;
END;
$$
LANGUAGE plpgsql;
SELECT merge_db(1, 'david');
SELECT merge_db(1, 'dennis');
因此,在您的情况下,您可以使用此功能或修改它以满足您的需要,然后进行批量函数调用。这是我能想到的在PostgreSQL中做你想做的最有效的方法。 (其他数据库具有可以更直接地处理此问题的SQL扩展。)
如果您希望插入在重复键上失败并且只想知道哪个成功并且哪个失败,您可以重写该函数以返回成功或失败布尔值,或者成功时返回null,并且失败时键ID。
答案 1 :(得分:0)
如果你不能采用OldPro建议的方法,试试这个:
创建一个List或Set,其中POJO只包含表中的Key列。现在为要在DB中更新/插入的所有POJO创建一个类似的列表。
循环数据库中的POJO集合,然后从您已经存在于数据库中的to_insert_or_update列表中丢弃任何POJO。
这样,批量更新将相当顺利,除非有其他应用在同一组记录上进行插入/更新。