What happens when I call one transactional method from another transactional method, now my second transactional method completed, and it came back in 1st transactional method, and unfortunately it fail, so will it roll back everything, means will it roll back 2nd transactional method changes..?? Note: both method are in same class
#Transactional
public void method1(){
//do something
call method2();
//do something
...
...
failed here
}
#Transactional
public void method2(){
//do something
save()
}
So in above example will it rollback whatever I saved in 2nd transactional method?
It depends on the txType. By default it is REQUIRED. So the first method starts the transaction and the same transaction is used for the call to method2.
Also be careful that a method call inside the same object does not trigger the transaction processing. As typically the transaction handling is handled as proxy that only works when calling an injected other bean. In your example you would not notice a difference though.
A case where this would matter is if method1 is not #Transactional and method2 is. In this case there would be no transaction at all.
If both methods are in the same class, the #Transactional annotation won't even be considered when calling from another method of the same class. It doesn't matter what you put there, or even if you leave it out. There still will be a transaction started by method1(), but then you're stuck in that transaction.
If the second method were in a separate class, you could use Propagation.REQUIRES_NEW to have it run in its own transaction, meaning that even if method1() later on failed, any changes in method2() would still have made.
The default transaction propagation of REQUIRED starts a new transaction if none exist, or joins an existing transaction. Again, in the separate class situation it results in the rollback of any changes made in method2() when method1() fails.
Spring boot provides concept of propagation with #Transactions. Propagation level decides that inner transaction should be part of same outer transaction or it should be different isolated one. By default propagation level is REQUIRED which means inner transaction will be part of same outer transaction, so if inner transaction fails whole transaction will get rollback.
Now its important to know that Rollback works for only Runtime exceptions by default. For checked Exceptions you have to specify that explicitly #Transcations(rollbackFor = Exception.class)
So to answer for your question is YES! It does rollback changes made by inner transaction.
this is a typical question:
You should call method2() by self injected object or use this notation, because another ways will call method2 and avoid call proxy object method, which contain all transactional logic.
In proxy mode (which is the default), only external method calls coming in through the proxy are intercepted. This means that self-invocation, in effect, a method within the target object calling another method of the target object, will not lead to an actual transaction at runtime even if the invoked method is marked with #Transactional. Also, the proxy must be fully initialized to provide the expected behaviour so you should not rely on this feature in your initialization code, i.e. #PostConstruct
Nested Transaction behaviour depends on #Transactional parameters. For example - Use PROPAGATION_REQUIRES_NEW for create new transaction for nested methods with #Transactional. See more info in official doc
What happens depends on the chosen transaction propagation. Default is: "REQUIRED" which means that if no transaction exists it will be started.
So in your code method2 will join existing transaction created for method1.
As for your case with both methods in the same class, be careful as this will not work as you expect because of the way Spring proxy objects work.
It depends on your transaction propagation config.
Related official doc is here
https://docs.spring.io/spring/docs/current/spring-framework-reference/html/transaction.html#tx-propagation
Just note the graph, propagation define a transaction's "transaction context".
Related
I have a Java, Spring Data application with a PostgreSQL DB and I have a code similar to this in my service layer:
public void method1() {
PersonDto dto = method2();
method3(dto);
}
#Transactional
public PersonDto method2() {
Person p1 = personRepository.saveAndFlush(new Person());
return createPersonDto(p1);
}
#Transactional
public void method3(PersonDto p1) {
Person p2 = personRepository.findById(p1.getId());
if (p2 == null) {
System.out.println("Not in the DB");
} else {
System.out.println("In the DB");
}
}
Sometimes this code prints "Not in the DB", when I was expecting that it would always print "In the DB". My questions are:
This saveAndFlush is even necessary? Since I'm not reusing that Entity in the same transaction, I guess it would have the same effect as a save, right?
How to guarantee that the changes in method2 will be committed before method 3 calls it? So it will always print "In the DB"?
The fact that I'm converting my Entity to a DTO is what is messing this up? Maybe if I was passing the Entity itself it would work properly?
I'm thinking about #Transactional only in method1, or replacing #Transactional in method3 with #Transactional(isolation = Isolation.READ_UNCOMMITTED).
Any advice?
I can see a couple of reason why you're getting the results you describe.
One possibility is that #Transactional doesn't necessarily mean "execute this method in a totally separate transaction." The default propagation is REQUIRED, which will use an existing transaction if one is already active. So if method2() is called in a stack where a transaction was opened earlier, it won't create a new one (and thus the new entity won't be committed) until that original transaction is committed. If this is what's happening, one solution would be to change the propagation to REQUIRES_NEW:
#Transactional(propagation = REQUIRES_NEW)
Another possibility, which seems more likely, is that these methods are all in the same class. To understand why that fails, you have to understand how Spring implements handling of #Transactional (and most other behavioral annotations): using proxies. That means that only method calls that come through the proxy get the transactional behavior. That's the typical scenario when one object calls a reference it has to another; the reference is actually to the proxy, which intercepts the call and wraps the behavior (in this case, transactionality) around it. However, when calling methods within the same instance, there is no proxy in play (Spring doesn't/can't replace this with a reference to the proxy), and thus no transactional behavior.
There are a few ways to work around that, but first I would consider how to restructure my classes and methods to avoid it. If that's not reasonable, things like AspectJ, TransactionTemplate, and maybe some other ideas are discussed in this SO Q&A.
Addendum:
This question and its answers also talks about options to work around the proxying problem.
I want to know what actually happens when you annotate a method with #Transactional?
Of course, I know that Spring will wrap that method in a Transaction.
But, I have the following doubts:
I heard that Spring creates a proxy class? Can someone explain this in more depth. What actually resides in that proxy class? What happens to the actual class? And how can I see Spring's created proxied class
I also read in Spring docs that:
Note: Since this mechanism is based on proxies, only 'external' method calls coming in through the proxy will be intercepted. This means that 'self-invocation', i.e. a method within the target object calling some other method of the target object, won't lead to an actual transaction at runtime even if the invoked method is marked with #Transactional!
Source: http://static.springsource.org/spring/docs/2.0.x/reference/transaction.html
Why only external method calls will be under Transaction and not the self-invocation methods?
This is a big topic. The Spring reference doc devotes multiple chapters to it. I recommend reading the ones on Aspect-Oriented Programming and Transactions, as Spring's declarative transaction support uses AOP at its foundation.
But at a very high level, Spring creates proxies for classes that declare #Transactional on the class itself or on members. The proxy is mostly invisible at runtime. It provides a way for Spring to inject behaviors before, after, or around method calls into the object being proxied. Transaction management is just one example of the behaviors that can be hooked in. Security checks are another. And you can provide your own, too, for things like logging. So when you annotate a method with #Transactional, Spring dynamically creates a proxy that implements the same interface(s) as the class you're annotating. And when clients make calls into your object, the calls are intercepted and the behaviors injected via the proxy mechanism.
Transactions in EJB work similarly, by the way.
As you observed, through, the proxy mechanism only works when calls come in from some external object. When you make an internal call within the object, you're really making a call through the this reference, which bypasses the proxy. There are ways of working around that problem, however. I explain one approach in this forum post in which I use a BeanFactoryPostProcessor to inject an instance of the proxy into "self-referencing" classes at runtime. I save this reference to a member variable called me. Then if I need to make internal calls that require a change in the transaction status of the thread, I direct the call through the proxy (e.g. me.someMethod().) The forum post explains in more detail.
Note that the BeanFactoryPostProcessor code would be a little different now, as it was written back in the Spring 1.x timeframe. But hopefully it gives you an idea. I have an updated version that I could probably make available.
When Spring loads your bean definitions, and has been configured to look for #Transactional annotations, it will create these proxy objects around your actual bean. These proxy objects are instances of classes that are auto-generated at runtime. The default behaviour of these proxy objects when a method is invoked is just to invoke the same method on the "target" bean (i.e. your bean).
However, the proxies can also be supplied with interceptors, and when present these interceptors will be invoked by the proxy before it invokes your target bean's method. For target beans annotated with #Transactional, Spring will create a TransactionInterceptor, and pass it to the generated proxy object. So when you call the method from client code, you're calling the method on the proxy object, which first invokes the TransactionInterceptor (which begins a transaction), which in turn invokes the method on your target bean. When the invocation finishes, the TransactionInterceptor commits/rolls back the transaction. It's transparent to the client code.
As for the "external method" thing, if your bean invokes one of its own methods, then it will not be doing so via the proxy. Remember, Spring wraps your bean in the proxy, your bean has no knowledge of it. Only calls from "outside" your bean go through the proxy.
Does that help?
As a visual person, I like to weigh in with a sequence diagram of the proxy pattern. If you don't know how to read the arrows, I read the first one like this: Client executes Proxy.method().
The client calls a method on the target from his perspective, and is silently intercepted by the proxy
If a before aspect is defined, the proxy will execute it
Then, the actual method (target) is executed
After-returning and after-throwing are optional aspects that are
executed after the method returns and/or if the method throws an
exception
After that, the proxy executes the after aspect (if defined)
Finally the proxy returns to the calling client
(I was allowed to post the photo on condition that I mentioned its origins. Author: Noel Vaes, website: https://www.noelvaes.eu)
The simplest answer is:
On whichever method you declare #Transactional the boundary of transaction starts and boundary ends when method completes.
If you are using JPA call then all commits are with in this transaction boundary.
Lets say you are saving entity1, entity2 and entity3. Now while saving entity3 an exception occur, then as enitiy1 and entity2 comes in same transaction so entity1 and entity2 will be rollback with entity3.
Transaction :
entity1.save
entity2.save
entity3.save
Any exception will result in rollback of all JPA transactions with DB.Internally JPA transaction are used by Spring.
All existing answers are correct, but I feel cannot give this complex topic justice.
For a comprehensive, practical explanation you might want to have a look at this Spring #Transactional In-Depth guide, which tries its best to cover transaction management in ~4000 simple words, with a lot of code examples.
It may be late but I came across something which explains your concern related to proxy (only 'external' method calls coming in through the proxy will be intercepted) nicely.
For example, you have a class that looks like this
#Component("mySubordinate")
public class CoreBusinessSubordinate {
public void doSomethingBig() {
System.out.println("I did something small");
}
public void doSomethingSmall(int x){
System.out.println("I also do something small but with an int");
}
}
and you have an aspect, that looks like this:
#Component
#Aspect
public class CrossCuttingConcern {
#Before("execution(* com.intertech.CoreBusinessSubordinate.*(..))")
public void doCrossCutStuff(){
System.out.println("Doing the cross cutting concern now");
}
}
When you execute it like this:
#Service
public class CoreBusinessKickOff {
#Autowired
CoreBusinessSubordinate subordinate;
// getter/setters
public void kickOff() {
System.out.println("I do something big");
subordinate.doSomethingBig();
subordinate.doSomethingSmall(4);
}
}
Results of calling kickOff above given code above.
I do something big
Doing the cross cutting concern now
I did something small
Doing the cross cutting concern now
I also do something small but with an int
but when you change your code to
#Component("mySubordinate")
public class CoreBusinessSubordinate {
public void doSomethingBig() {
System.out.println("I did something small");
doSomethingSmall(4);
}
public void doSomethingSmall(int x){
System.out.println("I also do something small but with an int");
}
}
public void kickOff() {
System.out.println("I do something big");
subordinate.doSomethingBig();
//subordinate.doSomethingSmall(4);
}
You see, the method internally calls another method so it won't be intercepted and the output would look like this:
I do something big
Doing the cross cutting concern now
I did something small
I also do something small but with an int
You can by-pass this by doing that
public void doSomethingBig() {
System.out.println("I did something small");
//doSomethingSmall(4);
((CoreBusinessSubordinate) AopContext.currentProxy()).doSomethingSmall(4);
}
Code snippets taken from:
https://www.intertech.com/Blog/secrets-of-the-spring-aop-proxy/
The page doesn't exist anymore.
I know that having transaction attribute on a static method inside an EJB is incorrect. There won't be any exception thrown but the transaction attribute will not have any effect.
However, if an EJB has a method callMe() with a transaction attribute (let's say REQUIRED) and this method invokes a static method that is within the same EJB or another helper class, will the static method be part of the container transaction?
Yes, it will be inside the transaction. The transaction is open for that entire method and anything called inside of it will execute inside the transaction unless you use special transaction attribute methods like : NOT_SUPPORTED or REQUIRES_NEW obviously.
When one talks about EJBs, one talk about beans' instances and not about the class itself.
Furthermore, in an enterprise bean with container-managed transaction demarcation, the EJB container sets the boundaries of the transactions associated to the bean instance, either session or message-driven.
Finally, as the EJB 3.2 spec states, since the transaction attributes for the methods of a bean class may be specified on the class, the business
methods of the class, or both, and these methods can't be static, any static methods declared on the bean will not take part on the container-managed transactions.
As a side note, on the Revision History section of the EJB 3.2 specification (part A.8 Final Release Candidate), is mentioned the following:
Clarified that no-interface view and no-methods interface message listener methods are non-static public methods
I have a question about spring transaction propagation. I understand different Spring transaction propagation i.e. Propagation.REQUIRED, Propagation.REQUIRES_NEW etc. What I am not clear about is how would it behave in case of nested transactions with different propagation values.
For example If I use #Transactional(propagation = Propagation.REQUIRED) to annotate a method m1. If I call a method m2 which is annotated as REQUIRES_NEW. What would be the behaviour? If an exception occurs in m2 will it rollback the changes in m2 and as well as m1 or only the changes of m1.
Similarly m1 annotated as REQUIRES_NEW and m2 as REQUIRED.
It's explained pretty well in the spring documentation for Transaction Propagation.
The propagation behavior of a method defines how Spring behaves upon entry/exit of that method and what happens if a transaction already exists (or does not exist) at that time.
The propagation behaviors of methods up the stack (whatever is calling your method) are irrelevant.
For your examples:
Outer (m1): REQUIRED
Inner (m2): REQUIRES_NEW
Result: A completely separate transaction will be created for m2 which can commit/rollback separately. m1 having REQUIRED is not relevant to m2.
Outer (m1): REQUIRES_NEW
Inner (m2): REQUIRED
Result: Spring will check that a transaction exists upon entering m2 or create one if none exists.
I'm using a Interface with #Transaction, and I have a method that performs a loop and check some information, but this loop takes long time to finish it, and i added a parameter in the database. And inside of the loop, is checked the parameter, and if is equal true, the loop will stop.
My problem is at the moment that check the parameter, it not get the parameter updated, it keep with the old value of the parameter.
is there a way to keep the transaction on interface and disable for specific method?
Try to split in two your method and you put "Requires new" on that check the parameters, in order to create a new transaction and suspend the current transaction if one exists.
#Transactional(propagation = Propagation.REQUIRES_NEW)
I hope I've given you all the answers about your question.
The first thing is undestand why you are using #Transaction on interfaces, beacause the correct way is to annote concrete classes (and methods of concrete classes) with the #Transactional annotation.
From spring references documentation:
Spring recommends that you only annotate concrete classes (and methods of concrete classes) with the #Transactional annotation, as opposed to annotating interfaces. You certainly can place the #Transactional annotation on an interface (or an interface method), but this works only as you would expect it to if you are using interface-based proxies. The fact that Java annotations are not inherited from interfaces means that if you are using class-based proxies ( proxy-target-class="true") or the weaving-based aspect ( mode="aspectj"), then the transaction settings are not recognized by the proxying and weaving infrastructure, and the object will not be wrapped in a transactional proxy, which would be decidedly bad.
Then can you share your code with us?