使用Hibernate JPA和Spring @Transactional
(使用Atomikos JTA实现)我的系统中有以下实体:
在使用addOrder
注释的Service类方法@Transactional
中,我希望在一个事务中执行以下步骤(它是一个原子功能块)。
在第1步(保留订单)我希望JPA在任何Exception
上回滚。
在第2步(保持订单行)我想在订单行的持续存在期间忽略任何错误。因此,如果我有10个订单行,1个因任何原因失败(例如违反约束),我想继续其他的。
在第3步如果有任何Exception
,我希望JPA回滚整个交易,以及在步骤1和2中完成的所有内容。
到目前为止我遇到的问题:
Exception
,则JPA将该事务标记为“仅回滚”。所以在此之后(和之前)的所有内容都会回滚,但我想在步骤2中忽略Exception
。flush()
或commit()
后才知道约束违规,这通常是在@Transactional
方法完成后。我需要在我的方法中知道它。@Transactional
方法中拆分每个步骤,但由于他们需要使用相同的Transaction
,因此这不会改变前两个问题。最佳方法是什么?
更新
我是否应该在Java中进行所有验证并手动检查记录是否已存在?
答案 0 :(得分:1)
将第二部分放在try-catch
块中。例如:方法体可能看起来像这样。
save(order);
flush();
for(Orderline line : orderlines) {
try {
orderlineService.save(line);
flush();
} catch(RuntimeException rte) {
continue;
}
}
save(customer);
答案 1 :(得分:0)
在第2步(保留Orderlines)我想忽略任何错误 在订单持续存在期间。所以,如果我有10个订单行和 1因任何原因失败(例如违反约束)我想 继续与其他人一起。
@Transactional默认是必需的。每个方法invocationg都会加入当前的Transaction,使所有3个操作都成为原子。
但在这种情况下,您应该使用REQUIRES_NEW创建一个可重入的方法,指示用于持久化每个Orderline的新事务:
@Transactional(readOnly = false, propagation = Propagation.REQUIRES_NEW)
public void persistMyOrderLine(OrderLine o) throws Exception{}
因为持续存在订单行的故障不应影响另一个,必须为每个订单创建一个新事务。因此,中止TransactionA-OrderLineA不会对TransactionB-OrderlineB产生影响。
问题:根据您的需要,本质上,操作不再是ATOMIC。因为您有一个忽略失败(订单行)的场景,操作不是ATOMIC,也不会中止角色过程(3个步骤)。
也许您应该检查这些需求。
答案 2 :(得分:0)
订单是否必要?步骤2可以成为第3步吗?
如果是这样,请执行步骤1& 3进入单个事务,并将每个人persist Orderline
放入其自己的事务中以便之后运行。当然,如果您需要回滚,如果所有订单行无法继续存在,这将无效...
另一种方法可能是创建一个非托管 EntityManager来处理您的Orderline
实体;启动事务,捕获异常,并为您自己管理提交/回滚。
理想情况下,您使用嵌套事务,JPA / JTA doesn't directly support。通过使外部事务的提交/回滚依赖于内部事务成功/失败 - 或忽略(在您的情况下)内部事务,您可以有一些外表。
“原子性”在实践中往往是一个相对的野兽 - 很大程度上取决于你的“交易隔离”的强度,并选择“锁定水平”(乐观或悲观的变化)。
我对此的初步想法是,如果你像线程同步问题那样接近它,并且在嵌套顺序上保持一定的一致性('外部'总是处理X,'内部'总是处理'Y') - 您应该没问题,因为应用更改的序列化订单将保持一致。