Reputation: 805
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
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
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