polis
polis

Reputation: 805

Spring transactions with caught Exceptions

Recently, I've been working with Spring boot + spring data jpa + hibernate. I faced one problem with spring transactions. Here is my service class and two questions:

@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.If method method_C() throws an Exception and I want to catch it and log it, the transaction is not rollbacked in method method_B(), because the Exception does not reach Spring framework. So how should I do in order to catch Exceptions from method_C() and at the same time do not lose capability of method method_B() be rollbacked?

2.Consider new method method_A().

public void method_A() {
   for(...) {
      ...
      ...
      method_B();
   }
}

I want invoke method_B() in a loop. If an exception occurs in a method_B() I want transaction of method_B() be rollbacked but method_A() should not exit and the loop should continue excuting. How can I achieve this?

Upvotes: 1

Views: 7471

Answers (2)

polis
polis

Reputation: 805

I solved my 2 problems this way: created another @Service class and moved method_B() into it. I've annotated this class as @Transactional. Now the method method_A() looks like this:

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

If RuntimeException occurs in the method_B() method, the exception is propertly logged, transaction of method_B() is rollbacked and the loop continuous. Thanks everybody for responses.

Upvotes: 7

Zeus
Zeus

Reputation: 6566

Instead of throwing exceptions do the following. (return error code).

Update: I read your question after posting. if you call method_b from method_A both are under same transaction. Unfortunately you cannot rollback the method_b changes alone. Spring considers it as one transaction if they are all under one service class. (all methods).

One thing you can try is the following.

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 <--

I hope it makes sense

Each of your methods a,b,c throw exceptions if it likes to be rolledback.

Update: another approach. This one is much better.

If each of your method are in a different service then you can use the following annotations of the spring to run each of the method in a different transaction boundaries

p v serviceA{

   @transactional
   method_a(){
       serviceb.method_b();
   }

}

p v serviceB{

   @Transactional(propagation=Propagation.REQUIRED)
   method_b(){

   }

}

more on it here

Spring transactional story here . Read the points below this article. Those are most important when developing the spring transactional app.

Upvotes: 1

Related Questions