【问题标题】:How to make one JPA repository Transactional but another not?如何使一个 JPA 存储库事务性但另一个不是?
【发布时间】:2016-09-09 11:06:45
【问题描述】:

我有尝试更改某些实体的方法,在此方法中我也想保存交易信息。 当发生任何异常时,我想回滚保存实体但仍想保存事务。 那么如何让一个实体存储库为事务存储库而不为事务存储库呢?

有来自仓库的代码

@Override
@Transactional(noRollbackFor=NotEnoughAmountInAccountException.class)
<T extends Transaction> T save(T transaction);

但这无济于事。 保存放置在最终块中的交易。

更新

我通过使用 AOP 解决了它。我在方面建议中创建事务对象并将其保存在 JPA 事务之外。

【问题讨论】:

  • 请提问,向我们展示异常跟踪...
  • 我添加了问题。没有堆栈跟踪,只是事务也因为回滚而没有保存。
  • 您可能想要做的是将存储库类保持原样,并拥有具有不同事务行为的服务方法,这样当您调用您的方法时,它会调用具有不同事务行为的其他服务方法(例如例如传播.REQUIRES_NEW)。这样您就可以保存“事务”,并且在任何未经检查的异常或NotEnoughAmountInAccountException 的情况下,外部事务可能会被回滚,但具有新行为的内部事务仍将被提交。
  • 它不起作用。据我了解,Spring 仅为公共方法创建代理方法,因此私有方法上的 @Transactional 不起作用。我不想公开它,因为有人可以在不保存交易的情况下调用它。
  • 能否请您发布您为解决问题所做的工作,并使用一些代码作为答案?并自己接受你的答案......它可能会帮助别人

标签: java spring hibernate transactions spring-data-jpa


【解决方案1】:

在新的@Transactional 中进行操作

@Transactional(propagation=Propagation.REQUIRES_NEW)
<T extends Transaction> T save(T transaction);

这将保存您的 transaction 元素,即使另一个 @Transactional 被回滚

【讨论】:

  • 可能是因为您从 spring-data 覆盖了默认的 save,即 @Transactional ...尝试在自定义方法中执行此操作,类似于名为 saveTransaction(T transaction) 的方法...它应该可以工作(当然,您必须实现该自定义方法)
  • 它也不起作用。据我了解,Spring 仅为公共方法创建代理方法,因此私有方法上的 @Transactional 不起作用。我不想公开它,因为有人可以在不保存交易的情况下调用它。
  • 哦,好吧,这是一个私有方法...然后@Transactional 将不起作用...您可以简单地删除私有方法上的注释...然后,我没有其他解决方案为你...顺便说一句:spring 为公共方法创建代理,是的,但如果你想在任何方法中使用Propagation.REQUIRES_NEW,它不应该与调用者在同一个类中,新的传播级别将也可以忽略
【解决方案2】:

我通过使用 AOP 解决了它。我在方面建议中创建事务对象并将其保存在 JPA 事务之外。

这是@Transactional方法

@SaveTransaction
@Transactional
public synchronized Transaction move(@NonNull String accountName, @NonNull String destinationName, @NonNull BigDecimal amount, String comment) {
    checkAmountIsPositive(amount);

    Account donor = getAccount(accountName);
    Account acceptor = getAccount(destinationName);

    if (!isEnoughAmount(accountName, amount)) throw new NotEnoughAmountInAccountException();

    BigDecimal newDonorAmount = donor.getAmount().add(amount.negate());
    BigDecimal newAcceptorAmount = acceptor.getAmount().add(amount);

    donor.setAmount(newDonorAmount);
    acceptor.setAmount(newAcceptorAmount);

    accountRepository.save(donor);
    accountRepository.save(acceptor);

    return null;
}

这是方面的建议

@Around("@annotation(com.softjourn.coin.server.aop.annotations.SaveTransaction)")
public Transaction saveTransaction(ProceedingJoinPoint joinPoint) throws Throwable {
    Transaction transaction = prepareTransaction(joinPoint);
    try {
        joinPoint.proceed();
        transaction.setStatus(TransactionStatus.SUCCESS);
        return transaction;
    } catch (Throwable e) {
        transaction.setStatus(TransactionStatus.FAILED);
        transaction.setError(e.getLocalizedMessage());
        throw e;
    } finally {
        transactionRepository.save(transaction);
    }
}

同样重要的是让这个建议的顺序高于@Transactional 的顺序,这样这个建议就会超过事务。 在方面类上设置@Order(100)。 默认情况下,它的订单较小,因此处于交易状态。

【讨论】:

    猜你喜欢
    • 2017-02-11
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-10-08
    • 1970-01-01
    • 2015-09-14
    • 2020-10-25
    相关资源
    最近更新 更多