【问题标题】:How to keep inserting rows after BatchUpdateException caused by primary key violation?如何在主键冲突导致的 BatchUpdateException 之后继续插入行?
【发布时间】:2017-05-30 15:49:29
【问题描述】:

问这个可能很傻,但我正面临这种情况:

我有一个表格,每次用户发送请求时我都会填充该表格,我在我插入的最后一行中的一个字段(日期)上使用日期。问题是,我插入的最后一行总是会尝试插入自己,因为它在我正在考虑的范围内。我知道一个解决方案可能只是在最后一行增加一两分钟,但我的问题由此而来。 我如何在 java 中使用 PreparedStatement 和批处理插入多行,跳过向我发送 PRIMARY_KEY_VIOLATION 异常的行,并继续插入正常的行? 我的意思是,例如,我的表中有一行“runner”,值为 25,这是我的主键,然后我想插入这些行: (25,26,27) 无法插入 25 个值,所以我想捕获异常并做一些事情来继续插入 26 和 27 个值。 可能吗?

感谢您的帮助和 cmets。提前谢谢!

【问题讨论】:

  • 参见BatchUpdateException API。您的建议可能是可能的,但会非常丑陋。避免PK违规。创建一个序列,以便您可以“INSERT INTO TABLE T SELECT MYSEQUENCE.NEXTVAL, OTHER_FIELD1, OHTER_FIELD2 WHERE ...
  • @AndrewS - 使用序列并不能解决问题。当然,它会生成一个唯一值,但您刚刚插入了一条带有无意义技术密钥的重复记录。
  • 问题是,你为什么要选择一个已经插入的行?当然,您需要解决的问题是获取有效的数据源,而不是处理数据目标中的异常。
  • JDBC 驱动程序实现可以选择在出错时停止或在出错时继续批量执行,但驱动程序必须始终使用相同的处理方式。甲骨文选择因错误而保释;没有办法改变这一点。

标签: java oracle jdbc primary-key


【解决方案1】:

我并不完全清楚您要达到的目标。数据库架构、代码和示例可能会有所帮助。但据我了解,我有以下提示:

  • 想想你的主键

    • 技术密钥应该是唯一的无需任何编程(如反复试验...)。时间戳通常不满足该标准。您的数据库的 sequence 数据类型GUID 是一个不错的选择,因为它们的用途是。

    • 非技术键应该代表整行特定行。日期/时间戳可能是表示日历应用程序中的一天或特定时间实例的可接受键。时间戳通常不代表“用户请求”。

  • 在事务中思考:数据库通常强调原子、事务操作。如果部分操作失败,您必须回滚整个事务。 正如 AndrewS 所指出的,在 BatchUpdateException 之后继续您的批处理可能是可能的(取决于驱动程序),但这绝对是不是一个好习惯。这是一种代码异味,表明您首先做错了什么。

  • 避免异常:对控制流使用异常也被认为是一种代码异味(参见 Java: Exceptions as control flow?,参考 Joshua Bloch 的“Effective Java”中的第 57 条)。在尝试操作之前检查导致异常的条件通常是首选。或者正如 APC 指出的那样:如果您知道您的代码会返回您插入的最后一行,为什么不将其从插入语句中删除?

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2020-01-13
    • 2021-01-11
    • 2013-04-05
    • 1970-01-01
    • 2012-06-23
    • 1970-01-01
    • 2015-01-05
    相关资源
    最近更新 更多