Java 带有捕获异常的Spring事务

Java 带有捕获异常的Spring事务,java,spring,hibernate,jpa,spring-data,Java,Spring,Hibernate,Jpa,Spring Data,最近,我一直在使用SpringBoot+SpringDataJPA+hibernate。我在spring事务中遇到了一个问题。这是我的服务课和两个问题: @Transactional @Service class MyService { @Autowired private MyRepository myRep; public void method_A() { try { method_C(); .....

最近,我一直在使用SpringBoot+SpringDataJPA+hibernate。我在spring事务中遇到了一个问题。这是我的服务课和两个问题:

@Transactional
@Service
class MyService {

    @Autowired
    private MyRepository myRep;

    public void method_A() {
       try {
          method_C();

          .....

          method_B();
       } catch(Exception e) {}
    }

    public void method_B() {
       Entity e = new Entity();
       e.set(...);

       myRep.save(e);
    }

    public void method_C() throws Exception {
       ....
    }
}
1.如果方法
method_C()
抛出异常,并且我希望捕获它并记录它,则不会在方法
method_B()
中回滚事务,因为异常不会到达Spring framework。那么,为了捕获
方法\u C()
的异常,同时不丢失方法
方法\u B()
的回滚功能,我应该怎么做

2.考虑新方法<代码>方法>()<代码> < /P>


我希望在循环中调用
方法B()。如果
方法\u B()
中发生异常,我希望回滚
方法\u B()
的事务,但
方法\u a()
不应退出,循环应继续执行。如何实现这一点?

请执行以下操作,而不是抛出异常。(返回错误代码)

更新:我在发布后阅读了您的问题。如果从方法_A调用方法_b,则两者都在同一事务下。不幸的是,您无法单独回滚方法更改。如果它们都在一个服务类下,Spring将其视为一个事务。(所有方法)

你可以尝试以下方法

request to--> Controller() ---> (spring opens transaction) service_method_a(); (spring closes transaction) 
               Controller() ---> (spring opens transaction) service_method_c(); (spring closes transaction)  
               Controller() ---> (spring opens transaction) service_method_b(); (spring closes transaction) 
return <--
更多信息


春天的故事。阅读本文下面的要点。在开发spring事务应用程序时,这些是最重要的。

不要抛出异常,而是执行以下操作。(返回错误代码)

更新:我在发布后阅读了您的问题。如果从方法_A调用方法_b,则两者都在同一事务下。不幸的是,您无法单独回滚方法更改。如果它们都在一个服务类下,Spring将其视为一个事务。(所有方法)

你可以尝试以下方法

request to--> Controller() ---> (spring opens transaction) service_method_a(); (spring closes transaction) 
               Controller() ---> (spring opens transaction) service_method_c(); (spring closes transaction)  
               Controller() ---> (spring opens transaction) service_method_b(); (spring closes transaction) 
return <--
更多信息


春天的故事。阅读本文下面的要点。这些在开发spring事务应用程序时最为重要。

我通过这种方式解决了我的两个问题:创建了另一个
@Service
类,并将
方法B()移入其中。我已经将这个类注释为
@Transactional
。现在方法
方法A()
如下所示:

public void method_A() {
   for(...) {
      ...
      try {
         anotherService.method_B();
      } catch (Exception e) {
         logger.error(...);
      }
   }
}

如果
method_B()
方法中发生
RuntimeException
,则会正确记录该异常,回滚
method_B()
的事务,并继续循环。谢谢大家的回复。

我这样解决了我的两个问题:创建了另一个
@Service
类,并将
方法B()
移入其中。我已经将这个类注释为
@Transactional
。现在方法
方法A()
如下所示:

public void method_A() {
   for(...) {
      ...
      try {
         anotherService.method_B();
      } catch (Exception e) {
         logger.error(...);
      }
   }
}

如果
method_B()
方法中发生
RuntimeException
,则会正确记录该异常,回滚
method_B()
的事务,并继续循环。谢谢大家的回复。

Zeus,谢谢你的回复,但是
method_B()
在异常情况下不会回滚,因为你已经用try-catch块包围了它的身体。值得一试,谢谢。另外,我想问一下你的陈述“如果你从方法A调用方法b,两者都在同一事务下。不幸的是,你不能单独回滚方法b的更改。如果它们都在一个服务类下,Spring将其视为一个事务。”如果这些方法在同一事务下,那么,为什么我们可以在方法(而不是类)之前添加带有不同参数(传播、隔离等)的
@Transactional
注释呢?是因为我们希望不同方法中的事务必须有不同的行为吗?@polis我已经更新了答案。请参考最后的链接来解释我想说的话。它已经在某个地方得到了回答,所以,我不想再费劲解释了。宙斯,谢谢你的回答,但是
method_B()
在异常情况下不会回滚,因为你已经用try-catch块包围了它的身体。值得一试,谢谢。另外,我想问一下你的陈述“如果你从方法A调用方法b,两者都在同一事务下。不幸的是,你不能单独回滚方法b的更改。如果它们都在一个服务类下,Spring将其视为一个事务。”如果这些方法在同一事务下,那么,为什么我们可以在方法(而不是类)之前添加带有不同参数(传播、隔离等)的
@Transactional
注释呢?是因为我们希望不同方法中的事务必须有不同的行为吗?@polis我已经更新了答案。请参考最后的链接来解释我想说的话。它已经在某个地方得到了回答,所以,我不会再费劲地解释它了。不要捕获异常,spring无论如何都会记录异常,包括完整的堆栈跟踪,所以为什么要自己动手呢。对于选项2,只需在For循环中放置一个try/catch。方法B仍按原样运行(包括回滚),方法a仍在继续。如果您想要一些额外的异常处理,您可以总是编写一个后抛出方面来进行日志记录,或者添加一个catch,但总是重新抛出异常(但由于Spring已经记录了,这将是一个冗余的异常)。如果我在循环中添加
try catch
块,则事务不会在
方法_B()
中回滚。实体被保存并提交到数据库。这里的假设是methodA不在事务中,只有MethodB。您的意思是,如果只在method
method_B()
之前写入
@Transactional
,它的行为应该像您所说的那样?不,因为这将是一个内部方法调用,因为Spring默认情况下,使用代理将根本没有事务。您可以在使用提前期或编译期编织时执行此操作