当前位置: 首页 > 知识库问答 >
问题:

@Transactional的奇怪行为(传播=传播。需要新)

聂炜
2023-03-14

这是我的问题:

我正在Java EE/Spring/Hibernate应用程序上运行批处理。此批处理调用方法1。该方法调用方法2,该方法可以引发用户异常(扩展RuntimeException的类)。下面是它的样子:

@Transactional
public class BatchService implements IBatchService {
 @Transactional(propagation=Propagation.REQUIRES_NEW)
 public User method2(User user) {
   // Processing, which can throw a RuntimeException
 }

 public void method1() {
   // ...
   try {
     this.method2(user);
   } catch (UserException e) {
     // ...
   }
   // ...
 }
}

在继续执行时捕获异常,但在事务关闭时,method1结束时抛出回滚异常。

这是堆栈跟踪:

org.springframework.transaction.TransactionSystemException: Could not commit JPA transaction; nested exception is javax.persistence.RollbackException: Transaction marked as rollbackOnly
    at org.springframework.orm.jpa.JpaTransactionManager.doCommit(JpaTransactionManager.java:476)
    at org.springframework.transaction.support.AbstractPlatformTransactionManager.processCommit(AbstractPlatformTransactionManager.java:754)
    at org.springframework.transaction.support.AbstractPlatformTransactionManager.commit(AbstractPlatformTransactionManager.java:723)
    at org.springframework.transaction.interceptor.TransactionAspectSupport.commitTransactionAfterReturning(TransactionAspectSupport.java:393)
    at org.springframework.transaction.interceptor.TransactionInterceptor.invoke(TransactionInterceptor.java:120)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:172)
at org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:202)
at $Proxy128.method1(Unknown Source)
at batch.BatchController.method1(BatchController.java:202)

当method2不抛出这个异常时,它工作得很好。

我尝试过的:

  • 设置@Transactional(noRollbackFor={UserException.class})方法1
  • 尝试并抓住方法2

但这并没有改变任何事情。

由于异常是在发生回滚的另一个事务中引发的,我不理解为什么它不起作用。我看了一下这个:Jpa事务javax。坚持不懈回滚异常:事务标记为rollbackOnly,但它并没有真正帮助我。

如果有人能给我一个线索,我将不胜感激。

更新

我通过设置传播=传播来使它工作。REQUIRES_NEW方法2调用的方法上(实际上是发送异常的方法)。这个方法是在一个与我的BatchService非常相似的类中定义的。所以我不明白为什么它在这个级别上工作,而不是在方法2上。

  • 我已经将方法2设置为公共的,因为如果方法如文档中所述是私有的,则不考虑注释

@Transactional注释可以放在接口定义、接口上的方法、类定义或类上的公共方法之前。

  • 我还尝试使用异常而不是运行时异常(因为它更合适),但它也没有改变任何事情

即使它起作用了,问题仍然悬而未决,因为它有一种奇怪的行为,我想理解为什么它的行为不应该如此。

共有1个答案

任云瀚
2023-03-14

缺省情况下,Spring事务通过用处理事务和异常的代理包装Spring bean来工作。当您从方法1()调用方法2()时,您完全绕过了此代理,因此它无法启动新事务,并且您实际上是从与调用方法1()打开的事务相同的事务调用方法2()

相反,当您从method1()调用另一个注入bean的方法时,实际上是在事务代理上调用方法。因此,如果这个外来方法被标记为REQUIRES\u NEW,那么代理将启动一个新事务,您可以在method1()中捕获异常并恢复外部事务。

文档中对此进行了描述。

 类似资料:
  • 问题内容: 我正在尝试使用命令模式来允许我的Web层在单个事务的上下文中使用Hibernate实体(从而避免延迟加载异常)。但是,我现在对如何处理交易感到困惑。 我的命令调用带有注释的服务层方法。这些服务层方法中的某些方法是只读的,例如,而某些方法是读/写的。 我的服务层公开了一个命令处理程序,该命令处理程序代表Web层执行传递给它的命令。 我认为我对使命令处理程序的方法具有事务性是正确的。这就是

  • 在下面的文章中说, 在此处输入链接描述 需要传播–支持当前交易;如果不存在,请创建一个新的。 下面是一个产品代码,然后是两个表的产品详细信息。 我的问题是什么时候会发生这种行为?我的意思是,当前交易怎么会结束?是在保存还是更新之后? 如果我们使用PROPAGATION_REQUIRED假设当前事务在插入产品后结束。然后一个新的事务来了,但是如果插入产品数量时出现任何故障,它只会回滚数量而不是输入的

  • 在以下代码方法中,更新正确的sql,但sql有一些问题,但是,当我调用doService()时,它必须将更新提交到DB,即使doService 2()有sql异常,因为doService 2()有一个新的传播类型,但是当我取消这个更新时,不会提交DB。。 正如你们的建议,以以下方式进行测试,但仍然面临相同的问题。这里i在一个单独的类中,但即使仍然存在与上述相同的问题

  • 我有一个部分在我的应用程序,加载媒体播放器与URL在回收者视图。有时播放url mp3不是一个有效的文件,但我需要显示它没有任何东西既不播放mp3文件当然,因为它已经无效。我的问题是媒体播放器不能正常工作时使用即使它是一个有效的文件mp3它不工作,我知道它是因为重新加载相同的文件有时工作,有时不工作。代码>准备方法工作完美和准备Async不正常工作

  • 我们目前正在使用侦探2.2.3. RELEASE,我们看不到在超文本传输协议标头中传递的字段userId没有传播。下面是我们的代码。 我们怀疑YML文件中的某些问题。我们尝试了以下所有选项,但均无效。 在回退中: %X{行李用户ID:-} 我们在超文本传输协议头中传递userId。

  • 当异常被抛出到组播中时,Camel不会传播异常。 在以下设置下,从其beanref引发异常: 为什么我不能向父路由提出多播异常? 骆驼2.17-快照