简体   繁体   English

春季JPA @交易原子

[英]Spring JPA @Transactional Atomic

Using Hibernate JPA and Spring @Transactional (with Atomikos JTA implementation) I have the following Entities in my system: 使用Hibernate JPA和Spring @Transactional (通过Atomikos JTA实现),我的系统中具有以下实体:

  • Order 订购
  • Orderline (holds a reference to the order) 订单行(包含对订单的引用)
  • Customer 顾客

In a Service class method addOrder annotated with @Transactional I want to perform the following steps, in one transaction (it's one atomic function block). 在一个用@Transactional注释的Service类方法addOrder ,我要在一个事务中执行以下步骤(这是一个原子功能块)。

  1. Persist the Order 坚持命令
  2. Persist the Orderlines 坚持秩序
  3. Persist the Customer 坚持客户

At step 1 (persisting the Order) I want JPA to rollback on any Exception . 在第1步 (坚持订单)上,我希望JPA在任何Exception上回滚。

At step 2 (persisting the Orderlines) I want to ignore any errors during the persisting of an orderline. 在第2步 (坚持订单行)中,我想忽略订单行保留期间的所有错误。 So if I have 10 orderlines and 1 fails for any reason (constraint violation for example) I want to continue with the others. 因此,如果我有10条订单行而1条由于任何原因而失败(例如,违反约束),我想继续与其他人联系。

At step 3 In case of any Exception I want JPA to rollback the entire transaction, so also everything that was done in step 1 and 2. 在第3步中,如果发生任何Exception我希望JPA回滚整个事务,因此也要回滚在第1步和第2步完成的所有操作。

Problems I ran into, so far: 到目前为止,我遇到的问题:

  • JPA marks the transaction as 'rollback only' in case of an Exception . 如果发生Exception JPA将事务标记为“仅回滚”。 So everything after (and before) this is rolled back, but I want to ignore the Exception at step 2. 因此,这之后(和之前)的所有内容都会回滚,但是我想在步骤2忽略Exception
  • JPA only knows about the constraint violation after a flush() or commit() is called, which is usually after the @Transactional method is finished. JPA仅在调用flush()commit()之后才知道约束违例,通常是在@Transactional方法完成之后。 I would need to know it inside my method. 我需要在我的方法中知道它。
  • Tried to split each step in a separate @Transactional method, but since they need to use the same Transaction this doesn't change the previous two issues. 试图将每个步骤拆分为单独的@Transactional方法,但是由于它们需要使用相同的Transaction因此不会更改前两个问题。

What is the best approach for this? 最好的方法是什么?

Update 更新

Should I put all validation in Java and manually check if a record already exists for example? 我是否应该将所有验证都放在Java中并手动检查记录是否已存在(例如)?

Put the second part in a try-catch block. 将第二部分放在try-catch块中。 For ex: The method body would probably look like this. 例如:方法主体可能看起来像这样。

save(order);
flush();
for(Orderline line : orderlines) {
    try {
        orderlineService.save(line); 
        flush();   
    } catch(RuntimeException rte) {
        continue;
    }
}
save(customer);

At step 2 (persisting the Orderlines) I want to ignore any errors during the persisting of an orderline. 在第2步 (坚持订单行)中,我想忽略订单行保留期间的所有错误。 So if I have 10 orderlines and 1 fails for any reason (constraint violation for example) I want to continue with the others. 因此,如果我有10条订单行而1条由于任何原因而失败(例如,违反约束),我想继续与其他人联系。

@Transactional is by default REQUIRED. 默认情况下,@ Transactional是必需的。 Each method invocationg joins the current Transaction making all 3 operations atomic. 每个方法调用g都会加入当前的Transaction,从而使所有3个操作成为原子操作。

But in this case you should create a reentrant method using REQUIRES_NEW, indicating a new transaction for persisting each Orderline: 但是在这种情况下,您应该使用REQUIRES_NEW创建一个可重入方法,指示用于保留每个订单行的新事务:

@Transactional(readOnly = false, propagation = Propagation.REQUIRES_NEW)
public void persistMyOrderLine(OrderLine o) throws Exception{}

because failures persisting an orderline should not impact on another, a new transaction must be created for each one. 因为持续存在订单项的故障不会影响另一个订单项,所以必须为每个订单项创建一个新事务。 So, aborting the TransactionA-OrderLineA does not impacts on TransactionB-OrderlineB. 因此,中止TransactionA-OrderLineA不会影响TransactionB-OrderlineB。

The problem is : with your needs, by nature, the operation is not ATOMIC anymore. 问题是 :根据您的需求,该操作本质上不再是ATOMIC。 Because you have a scenario that a failure (orderline) is ignored, the operation is not ATOMIC and will not abort the role process (3 steps). 因为您遇到的情况是忽略了失败(订单行),所以该操作不是ATOMIC,并且不会终止角色过程(3个步骤)。

Maybe you should review these needs. 也许您应该查看这些需求。

Is the order necessary? 是否需要订购? Can Step 2 become Step 3? 步骤2可以变成步骤3吗?

If so, put steps 1 & 3 into a single transaction, and each individual persist Orderline into it's own transaction to be run afterwards. 如果是这样,则将第1步和第3步放入一个事务中,每个人都将persist Orderline到它自己的事务中,然后再运行。 Of course, this won't work if you need to rollback if all Orderlines fail to persist... 当然,如果您在所有订单行都无法持续运行时需要回滚,则无法使用此功能...

Another approach may be to create an unmanaged EntityManager for working with your Orderline entities; 另一种方法可能是创建一个非托管的 EntityManager来处理您的Orderline实体; start transactions, catch exception, and manage commit/rollback on your own for them. 开始交易,捕获异常并自行管理提交/回退。

Ideally you'd use a nested transaction, which JPA / JTA doesn't directly support . 理想情况下,您将使用JPA / JTA不直接支持嵌套事务。 You can have some semblance by making the outer transaction's commit/rollback dependent on the inner transactions success/failure - or ignore (in your case) the inner transaction. 通过使外部事务的提交/回滚取决于内部事务的成功/失败,可以有一些相似之处-或忽略(在您的情况下)内部事务。

"Atomicity" tends to be a relative beast in practice - dependent much on the strength of your "transaction isolation" and chosen "locking level" (optimistic or pessimistic w/ variations). 在实践中,“原子性”往往是一个相对的野兽-很大程度上取决于“事务隔离”的强度和选择的“锁定级别”(带有变化的乐观或悲观)。

My initial thoughts on this is that if you approached this like a thread-synchronization problem, and maintained some consistency on the order of nesting ('outer' always dealing with X, and 'inner' always dealing with 'Y') - you should be OK because the serialized order in which changes are applied would remain consistent. 我最初的想法是,如果您像线程同步问题那样处理此问题,并在嵌套顺序上保持一定的一致性(“外部”始终与X交互,“内部”始终与“ Y”交互),则应该可以,因为应用更改的序列化顺序将保持一致。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM