【发布时间】:2014-07-01 23:27:59
【问题描述】:
我有带有验证注释的实体,例如@NotNull。我不知道如何防止容器管理的事务在批量持久操作中出现 ConstraintViolationException 的情况下回滚,例如:
public void persistAll(List<TheEntity> entities) throws Exception{
for(TheEntity ent : entities){
em.persist(ent);
}
}
将持久化操作包装在 try-catch 中并不能解决问题,因为即使捕获了约束异常,事务也会被标记为回滚(不会保留任何其他“已验证”实体)。我可以隔离每个实体的事务以保持持久,但我认为这会对性能产生很大影响(对此不确定,我正在使用 eclipselink 和批处理 JDBC 优化)。
我知道 ContraintValidationException 的行为符合 JPA 规范的要求(标记回滚),但我不确定我是否了解 eclipselink 批量优化的工作原理(批量操作是否需要在单笔交易?)。
感谢您的关注。
问候。
编辑:Welp,eclipelink 文档指出“批量写入可以通过在单个事务中而不是单独向数据库发送 INSERT、UPDATE 和 DELETE 语句组来提高数据库性能。”,所以是的,它需要在单个事务中完成。
编辑:我还可以从上下文中注入一个约束验证器并禁用 persistence.xml 上的 JPA 验证器,这样我就可以在 JPA PrePersist 操作之前验证实体列表。但是,这将影响不需要对其进行批量操作但仍需要验证的其他实体。啊!差不多了。
【问题讨论】:
-
只是为了确定,例如,您需要处理 4 个条目,而第三个条目抛出异常,您希望前 2 个更改提交并丢弃第 3 个和第 4 个?
-
我只想丢弃触发约束异常的实体。其余的必须坚持。我还发现我可以使用 flush 方法,但又一次不确定性能影响。
-
老实说,我对 JPA 了解不多,我只是来这里学习并可能贡献一点。你说 try catch 不起作用....你确定吗?如果你包围整个操作,那么它可能不起作用,那么只包围抛出异常的行(在循环内)呢?这样,您可能会选择忽略异常并继续进行您的交易。您还可以在 catch 中添加某种变量/缓冲区来记录循环期间发生的所有异常,并稍后针对这些异常执行您的操作。
-
好吧,规范规定如果发生 ContraintValidationException,事务将被标记为回滚。所以一旦火了,就什么也做不了。是的,我可以抓住它,但在那个时候没用。
-
这可能是一个无用的评论,但显然在这种特定情况下,您不想要持久性,而不是为什么使用 JPA :D 。好的,除了无用的评论,虽然这可能是一种效率较低的做事方式,也许你可以尝试像我建议的那样,但在捕获部分记录哪个实体有问题(通过列表索引?)然后一切都是回滚,如果检测到错误缓冲区不为空,从列表中删除实体并将列表放回方法中并再次运行?不确定你的表现。
标签: java jpa eclipselink java-ee-7