In the J2EE doc it says,
Although beans with container-managed transactions require less
coding, they have one limitation: When a method is executing, it can
be associated with either a single transaction or no transaction at
all.
Question 1. But what i understand is unless we declare transaction attribute with NotSupported or Never, when the method is executing (suppose with default Required attribute) its guaranteed the method to be run with in a transaction right?
Also I need to know suppose with container manager transaction with default Required attribute below pseudo code happening,
class bean1{
public void m1(){
bean2.m2();
}
}
class bean2{
public void m2(){
}
}
**Question 2.**In this case does m2() in bean2 ran with in a new transaction or ran under same transaction for m1() in bean1?
Question 1. But what i understand is unless we declare transaction
attribute with NotSupported or Never, when the method is executing
(suppose with default Required attribute) its guaranteed the method to
be run with in a transaction right?
Yes, the default for container-managed transaction is Required, which will start a transaction if one does not exist. The paragraph you quoted is somewhat unusual (obviously either a transaction exists or not), so I'm missing context to give a more complete explanation.
Question 2. In this case does m2() in bean2 ran with in a new
transaction or ran under same transaction for m1() in bean1?
Assuming they are both EJBs and no other transaction attributes are applied (i.e., both EJB methods are using the default Required attribute), then both methods will use the same transaction. The semantics for all the transaction attributes are described succinctly in the javadoc for TransactionAttributeType.
Related
I have this simplified escenario in a Spring application with Java and Hibernate for persistence provider:
#Transactional
void method1() { // some savings}
#Transactional
void method2() { // some savings}
When I run a parent method (not annotated as transactional)
void parentMethod() {
method1();
method2();
}
Can I make sure that when the method finishes the changes are impacted in the database immediately before the method is called?
Or that changes could be flush to database later, with some delay?
I'm interested on other applications seeing the changes made in database immediately when method1 finishes (and before method2 be called)
Update
My parent method is not defined in the same class, and the class and firm of the my parent method has not #Transactional annotation
Thanks!
To your question ... ensure the flush of data exactly when the method ends? No, not exactly when the method ends, but latest when the method ends.
Within transaction you can flush the current state as many times as you wish. Flushing means that you synchronize your JPA session with database. See Hibernate doc regarding this. Flushing does not mean your changes are durable; if transaction rolls back later on, these changes will be automatically reverted. The commit operation performs different steps, one of them is to ensure that the JPA (e.g. Hibernate) session is synchronized with DB, and, if needed, calls flush. If the session is already synchronized, flush will be skipped.
In the comments you wrote that the class and the method parentMethod are not transactional and that method1() and method2() are defined in a separate class. In such case when the method1() is called, a new transaction will be started. When this method ends, this transaction will be committed. Any changes in the database done by this method will be durable, i.e. no matter what happens later on (exceptions, roll backs in other methods) these changes will remain in the database.
Some information relevant to your case can be found here because following is important:
If these methods are in the same class or not and
If you use Spring own AOP or AspectJ. Besides it depends on the class where your parentMethod is defined. If it is transactional, then these 2 calls will run within the existing transaction and there will be no commit after the 1st one is committed.
In Spring, if I have:
ServiceA.serviceA() -> ServiceB.serviceB() -> ServiceC.serviceC() ->ServiceD.serviceD()
where ServiceD.serviceD() can throw a runtime exception: MyRuntimeException, which is propagated back up to ServiceA.serviceA catch block. Does it matter on which service I put #Transactional(noRollbackFor=[MyRuntimeException.class]) on?
Is there any difference between putting it on any of the services?
Note: All my Services are marked as #Transactional
As you did not give precision on that, I assume that you are using default propagation of PROPAGATION_REQUIRED. In that context, the 4 services will use the same transaction, and if any of the three inner marks the transaction as read-only as a result of the exception, the outer will get a UnexpectedRollbackException to inform it that the asked commit actually resulted in a rollback. From Spring Reference Manual : However, in the case where an inner transaction scope sets the rollback-only marker, the outer transaction has not decided on the rollback itself, and so the rollback (silently triggered by the inner transaction scope) is unexpected. A corresponding UnexpectedRollbackException is thrown at that point. This is expected behavior so that the caller of a transaction can never be misled to assume that a commit was performed when it really was not. So if an inner transaction (of which the outer caller is not aware) silently marks a transaction as rollback-only, the outer caller still calls commit. The outer caller needs to receive an UnexpectedRollbackException to indicate clearly that a rollback was performed instead.. And if the outer transaction decides to rollback the transaction because of the exception, the transaction will obviously be rolled back.
So if none of the services catches the exception, and if you use a propagation of PROPAGATION_REQUIRED, at least the four involved methods have to be annotated with #Transactional(noRollbackFor=[MyRuntimeException.class]).
An alternative of using noRollbackFor=[MyRuntimeException.class] would be to catch the exception in the appropriate method of ServiceD. In that case, the exception will never climb up the stack, and none of the transactional proxies will ever knows it occurred. The commit would then normally happen at the end of the transaction.
Edit per comment :
If you want further control on exception management, you could try to duplicate method : a transactional method, that calls a non transactional one in your service class. And you could call the non-transactional one if you do not want another transactional proxy in the chain. But this has sense only if this use case (a service class calling another service class with special exception requirement) is exceptional.
As an alternative, you could inject the implementations on the other service classes instead of injecting the transactional proxies (#Autowired private ServiceBImpl serviceB;). As you are already have a transaction obtained at the outer level, all DAO operations should be fine, and as there is only one transactional proxy at the outer level, you have one single point of control for exception management. It is rather uncommon to inject classes instead of interfaces, and you should document the why in a red flashing font :-) , but it should meet your requirements.
If you use a combination of
#Transactional(propagation = REQUIRES_NEW, noRollbackFor = MyRuntimeException.class)
then this service can commit independently from the rollback of the parent transaction (which will occur if it is not annotated with noRollbackFor). Otherwise you would have to mark all the transactional methods involved with the same noRollbackFor annotation.
I have a method that starts a transaction programmatically using transaction template from Spring.
Void methodA() {
TransactionTmeplate..........
Setpropgation to requires new....
/// do my stuff in trasaction
}
So if I have another class which calls this method it creates a transaction, as I would expect. But what happens if this method is entered again from the same calling thread. Does another transaction get created?
Example:
MethodCaller -> methodA (transaction created) -> methodD -> methodA(??)
Following on:
Also if class is #autowired, would two calling threads ever share the same transaction, considering one instance exists?
I would assume not as they have there own own entry on the stack for the method.
The javadoc on Propagation.REQUIRES_NEW is pretty clear, I am not sure whether it could be better explained.
As for the different threads calling your method: the TransactionManager will make sure that threads won't interleave with each other regarding transactions.
But having a method that is re-entrant and always starts a new transaction indicates that your application is not properly layered. Try to do some refactoring, and make sure that the method responsibile for starting a new transaction never gets called recursively.
In first case study given at http://www.vermatech.com/code/SpringTransactionExamples.html,
program is calling two methods i.e.
testModel.deleteAllCountries();
testModel.initializeCountries();
where initializeCountries throws runtime exception. For both methods' transaction definition attribute is PROPAGATION_REQUIRED. Still transaction under deleteAllCountries
method gets committed but transaction under initializeCountries are rolled back(as per the logs given in the same case study).
As per PROPAGATION_REQUIRED definition is that it Support a current transaction; create a new one if none exists. So my question here is transaction under initializeCountries method
should support the transaction under deleteAllCountries method. I mean both method should be treated as single transaction. As per my understanding either complete transaction should be committed or rolled back? Not sure how come logs are treating them separately.
"Propagation required" is defined as
Support a current transaction, create a new one if none exists.
In your case above the deleteAllCountries method executes in a transaction and commits. There is no current transaction when initializeCountries is called, so it executes in a second transaction, and rolling it back has no effect on the changes made by the first method.
Propagation applies to nested method calls, not to successive ones. If you look at the documentation:
When the propagation setting is PROPAGATION_REQUIRED, a logical
transaction scope is created for each method upon which the setting is
applied. Each such logical transaction scope can determine
rollback-only status individually, with an outer transaction scope
being logically independent from the inner transaction scope. Of
course, in case of standard PROPAGATION_REQUIRED behavior, all these
scopes will be mapped to the same physical transaction. So a
rollback-only marker set in the inner transaction scope does affect
the outer transaction's chance to actually commit (as you would expect
it to).
However, in the case where an inner transaction scope sets the
rollback-only marker, the outer transaction has not decided on the
rollback itself, and so the rollback (silently triggered by the inner
transaction scope) is unexpected. A corresponding
UnexpectedRollbackException is thrown at that point. This is expected
behavior so that the caller of a transaction can never be misled to
assume that a commit was performed when it really was not. So if an
inner transaction (of which the outer caller is not aware) silently
marks a transaction as rollback-only, the outer caller still calls
commit. The outer caller needs to receive an
UnexpectedRollbackException to indicate clearly that a rollback was
performed instead.
then you can see all of this is about inner- and outer-, none of it mentions successive calls. In your case the call to deleteAllCountries is the outermost transactional method, so when it finishes successfully then Spring commits the transaction immediately. Then your call to initializeCountries has to be executed within a separate transaction, where it is the outermost method.
Your assumption seems to be that Spring will hold the transaction open after the first method finishes, but that's not how it works. In order to get the effect you want, you could create another method on testModel that wraps the calls to deleteAllCountries and initializeCountries, make that method transactional and give it the attribute PROPAGATION_REQUIRED. That way a rollback of the second method will cause the first method's changes to be rolled back too, because the wrapping method is grouping them together. Otherwise nothing is telling Spring these things should be part of the same transaction.
I am using annotation based declarative approach for spring aop.
sample code
ClassA{
#Transactional(readOnly = false, propagation = Propagation.REQUIRES_NEW)
add()
{
method1();
method2();
method3();
}
}
But I have still doubt on use of propagation.does propagation.Requires_New means that each request will start new transaction.
Second question:
Does failure of any method like method2,method3 will cause the transaction to rollback?
I will be very happy if any can help me to leans transaction propagation.
can someone provide me a real world example where we need a participate in existing transaction.because I visualise that add function that we are using in above example will be independent for all users,or any other function will be independent to each user who is calling. I am not able to find example where other propagation behaviour like PROPAGATION_SUPPORTS ,PROPAGATION_MANDATORY,PROPAGATION_REQUIRES_NEW etc. are used
Answering this comment, not the actual question:
transaction are session specific or
request specific – Vish 3 hours ago
Neither. request and session are both web-specific scopes, while the Spring Transaction abstraction has nothing to do with web technologies.
The scope of #Transactional is per method invocation, as #Transactional is implemented through Spring AOP. The transactional state is kept in ThreadLocal variables which are initialized when the outermost #Transactional method is entered and cleared with commit or rollback when it is left. This whole abstraction works on Java method level, and hence does not require or profit from a web container.
And in response to this Question in the comment below:
thanks #sean,i am stil not able to get
answer where other propagation
behaviour like PROPAGATION_SUPPORTS
,PROPAGATION_MANDATORY,PROPAGATION_REQUIRES_NEW
etc are used. please refer above for
whole question
Here's the list of Propagation values with my comments:
MANDATORY
Support a current transaction, throw an exception if
none exists.
Does not start a new Transaction, just checks whether a transaction is active (must be inside either another #Transactional method call or a programmatically created transaction)
NESTED
Execute within a nested transaction if a current transaction
exists, behave like
PROPAGATION_REQUIRED else.
Start a nested transaction if a transaction exists, start a new transaction otherwise.
NEVER
Execute non-transactionally, throw an exception if a transaction
exists.
Does not start a transaction. Fails if a transaction is present.
NOT_SUPPORTED
Execute non-transactionally, suspend the current transaction if one
exists.
Does not start a transaction. Suspends any existing transaction.
REQUIRED
Support a current transaction, create a new one if none
exists.
If a transaction exists, use that, if not, create a new one. In 95% of cases, this is what you need.
REQUIRES_NEW
Create a new transaction, suspend the current transaction if one
exists.
Always creates a new transaction, no matter if an existing transaction is present. If there is, it will be suspended for the duration of this method execution.
SUPPORTS
Support a current transaction, execute
non-transactionally if none exists.
Can use a transaction if one is present, but doesn't need one (and won't start a new one either)
In most cases, REQUIRED is what you need (hence it's the default in the #Transactional annotation). I have personally never seen any other value but REQUIRED and REQUIRES_NEW in use.
Transaction propagation indicates what should be the behaviour of the given method when it is invoked. REQUIRES_NEW means that a new transaction should always be started, even if there is an ongoing transaction.
If method1(), for example, defines REQUIRES_NEW, than it will execute in a new transaction.
An exception will rollback the current active transaction, yes.
Yes. Requires_New means that each request will start new transaction. and Yes failure in method2,method3 will cause the transaction to rollback, depending on the rollback properties.
check Transactional properties.