What is the best practice on implementing a transaction restart upon deadlock or lock timeout exceptions when using Spring (specifically the Spring recommended approach: declarative transactions) ?
Thanks,
Asaf
I feel like Spring itself should have a good answer to this question (in the form of documentation, at the least, or a retry interceptor of some sort). Alas, it does not.
Probably the best way to handle retries (if you want to continue being "declarative" about things) is to write your own interceptor implementation that will automatically retry the transaction a configured number of times. For starters, study Spring's TransactionInterceptor, which manages begin/rollback/commit behavior for declarative transactions. If you're using Hibernate, note how it handles Hibernate session binding/unbinding to the current Thread.
Things to watch out for if you're using Hibernate:
Your "retry interceptor" should be sure to unbind any preexisting thread-bound Hibernate session and rebind a new one. Once an exception (e.g., deadlock) is thrown from within Hibernate/JDBC code the corresponding Hibernate session is poisoned and needs to be discarded. (session.clear() is not sufficient.)
Be careful if your transactional service methods use Hibernate session objects as method parameters. On retry, when you reset your Hibernate session, these objects will be detached. You'll need to reattach them if the service method assumes they are attached (e.g., if they use lazy loaded properties that get accessed in the service method, or if you try to save them, etc.) In general, it's better if you don't use Hibernate objects as parameters to transactional service methods.
You'll be implementing MethodInterceptor.invoke() -- the MethodInvocation instance that gets passed in to this may be stateful; you may need to clone it before using it in the interceptor.
I recommend using the class org.springframework.retry.interceptor.RetryOperationsInterceptor from the spring retry project, configured like this:
<aop:config>
<aop:pointcut id="transactional" expression="execution(* com...*Service.remoteCall(..))" />
<aop:advisor pointcut-ref="transactional" advice-ref="retryAdvice" order="-1"/>
</aop:config>
<bean id="retryAdvice" class="org.springframework.retry.interceptor.RetryOperationsInterceptor"/>
But if you still want to implement it by yourself, the example of AOP from spring documentation is a good start.
There is no universal answer because it depends on application specifics. For example you may want to perform automatic transacted operation restart or notify the user about operation failure and ask for explicit retry confirmation etc.
I'd use AOP in case of automatic restart scenario.
I had the same question several years ago and ended up writing my own solution as an AOP aspect, which ends up looking like this in your code:
#RetryTransaction
#Transactional
public void doSomething() {
....
}
Related
I have a Spring Boot application with Hibernate, with a bunch of DAOs annotated with #Repository and Spring's #Transactional. Everything works fine. Then I decide to move common methods (persist, find, merge) to an AbstractDao. Writing operations (persist, merge) start throwing that No EntityManager with actual transaction available for current thread - cannot reliably process 'persist' call exception. I try adding #Transactional to AbstractDao, and contrary to my expectations, it fixes it.
Why is that so? I thought that since, unlike CGLIB, Spring uses interfaces instead of extending classes, it wouldn't work, and I would need to define an interface to declare instead of my DAOs. But I also guess that I'm mixing concepts of how Spring deals with dependency management and with transactions.
Can somebody provide an explanation of why does it work? Is there a better way of dealing with this problem?
I'm having a difficult time understanding Spring Transactions. First off, I am trying to use as little of Spring as possible. Basically, I want to use #Transactional and some of its injection capabilities with JPA/Hibernate. My transactional usage is in my service layer. I try to keep them out of test cases. I use CTW and am spring-configured. I have component scan on the root of my packages right now. I also am using Java configuration for my datasource, JpaTransactionManager, and EntityManagerFactory. My configuration for the JpaTransactionFactory uses:
AnnotationTransactionAspect.aspectOf().setTransactionManager( txnMgr );
I do not use #EnableTransactionManagement.
Unfortunately, I'm having a hard time understanding the rules for #Transactional and can't find an easy page that describes them simply. Especially with regards to Session usage. For example, what if I want to use #Transactional on a class that does not have a default no-arg constructor?
The weirdest problem I'm having is that in some of the POJO service classes Transacitonal works great while in others I can see the transactions being created but operations ultimately fall saying that there is "no session or the session has been closed". I apologize for not having code to reproduce this, I can't get it down to a small set. This is why I am looking for the best resources so I can figure it out myself.
For example, I can have a method that gets a lazily fetched collection of children, iterates through it and puts it into a Set and returns that set. In one class it will work fine while in another class also marked with #Transactional it will fail while trying to iterate through the PersistentSet saying that there is no session (even though there IS a transaction).
Maybe this is because I create both of these service objects in a test case and the first one is somehow hijacking the session?
By the way, I have read through the spring source transaction documents. I'm looking for a clear set of rules and tips for debugging issues like this. Thanks.
Are you sure you loaded your parent entity in the scope of the very transaction where you try to load the lazy children? If it was passed in as parameter for example (that is, loaded from outside your #Transactional method) then it might not be bound to a persistence context anymore...
Note that when no #Transactional context is given, any database-related action may have a short tx to be created, then immediately closed - disabling subsequent lazy-loading calls. It depends on your persistence context and auto-commit configurations.
To put it simply, the behaviour with no transactional context being sometimes unexpected, the ground rule is to always have one. If you access your database, then you give yourself a well-defined tx - period. With spring-tx, it means all your #Repository's and #Services are #Transactional. This way you should avoid most of tx-related issues.
I have a simple resource class that implements some POST method. How to rollback transaction if there was exceptions in my methods, and commit - if all is ok?
Is there a way to write this code once - not in every resource class that I have?
If you are using Spring, #Transactional will handle your scenario.
http://static.springsource.org/spring/docs/3.0.x/reference/transaction.html
Using a dependency-injection will greatly simplify this. Using #Transactional or similar annotations around the methods where you want to commit/rollback transactions.
If you have to do this manually, you have basically two options:
do it manually for every operation
use the proxy pattern/decorator pattern and proxy/decorate all your classes that require transactions. Then in the proxy/decorator start the transaction, delegate to the target, and commit it after it returns. (this is how DI frameworks do it)
I have been working for a while on a project with the following components:
Struts2.1.8.1,
Spring 3.0.3
JPA 2.0,
Hibernate 3
I am using Spring's EntityManager magic... But I'm having problems dealing with transactions inside my actions. For instance, I am setting values on my persisted object in several methods within my class, and I want to be able to rollback if the validate method finds a validation error, or commit these changes otherwise. I have already spent quite a long time reading half of the internet for a comprehensive explanation. Unfortunately, no complete examples exist (at least similar to my stack).
I have stumbled with this thread on a mailing list: #Transactional Spring Annotation in a Struts2 Action does not work. The message I'm linking at seems to have a pretty simple and straightforward solution, using a TransactionInterceptor will do the trick it seems... The problem is that I'm not finding useful information regarding this interceptor.
Anyone here has experience with this technology and can spare a tip and a link or two on how to use Spring transactions inside Struts2 actions?
Thanks!
- Edit 1 -
I have set up a test project if you are interested, just download the file and try it out (or inspect it). Thanks!
Generally, controllers/actions/backing beans/etc don't handle transactions. Actions are the web-part of your back-end code - they should only be concerned with gathering request data, and sending response data. The logic itself (including database access) should be done in another layer. E.g. a service layer. So you create another bean, inject it in the action, and make it do the work - userService.register(user). Then configuring transactions on a service layer should be trivial since it is both in the spring documentation and in countless examples:
<tx:annotation-driven /> and #Transactional (btw, make sure you have the <tx:..> now, it might be causing the issue. Even if it works, this does not invalidate my suggestion about the service layer)
I don't like answering my own question, but since I solved this ages ago... I thought I should share the knowledge (or lack of... in this case).
The book I was using to learn about Struts 2 and Spring-JPA-Hibernate, adds the #Transactional annotation right before the declaration of the service class. This is terribly wrong, for all methods (including those that only retrieve stuff from the database) are inside a committable transaction. Long story short everything got committed event if exceptions occurred.
The solution, as Bozho so wisely pointed out, was to look at examples. That is, set your transtactional methods carefully, in my case I set up transactions for the methods that had to write back to the database and everything started to work just fine.
Thanks to Steven and Quaternion too for taking the time to answer my question.
Based on your question, here's what I understand about your problem.
You want to wrap your action invocation in a transaction. If the validate method records validation errors, you want to roll the transaction back. Presumably, you also want to rollback in case of an error.
Solution
Create an interceptor that will:
Start a transaction
Invoke the action inside of a try/catch block
Rollback the transaction if there is an exception or if there are any validation errors on the action (this can be detected using action.hasErrors)
Commit the transaction
You will probably want this interceptor defined pretty early in the stack. I don't know of any pre-built interceptors for this (although there may be some), but it should be fairly easy to assemble.
Update
I don't use Spring, so I can't say how the JPA transaction support works there, but you can handle transactions for your EntityManager like:
try {
entityManager.getTransaction().begin();
// do your thing
entityManager.getTransaction().commit();
} catch (Exception e) {
entityManager.getTransaction().rollback();
throw new PersistenceException(e);
}
This is just a crude example, but it should illustrate the point.
If you have a call in a Dao method like (pseudo code):
return ..getHibernateTemplate( get by id );
Now say that entity has a lazy-loaded collection. Once you return from your Dao using the hibernateTemplate helper method, how come the session stays in scope and allows you to lazy-load a collection?
Is the session initialized and committed at a global level on a per request basis?
Update
Please explain where exactly the call to 'getcurrentsession' is made, and when is it actually closed/committed?
From what I understand, the spring framework has to handle the session lifecycle, where does it do this? at what point the in the requests lifecycle?
It is handling the Unit of work also, where/how?
Once you return from your Dao using the hibernateTemplate helper method, how come the session stays in scope and allows you to lazy-load a collection?
Because the Session hasn't been closed yet and your entity is thus still Persistent (as opposed to the Detached object state). As long as your entity has not been detached, you can lazy load collections and proxies. See chapter 10.1. Hibernate object states for more details on these states (it's very important to understand them and the terminology used).
Is the session initialized and committed at a global level on a per request basis?
With web applications, it's typically per request. As mentioned in the javadoc of HibernateTemplate:
Lazy loading will also just work with an open Hibernate Session, either within a transaction or within OpenSessionInViewFilter/Interceptor.
And if you look at the javadoc of OpenSessionInViewFilter or OpenSessionInViewInterceptor, you'll read that they are slightly different but both binds a Hibernate Session to the thread for the entire processing of the request and provide an implementation of the "Open Session in View" pattern.
Please explain where exactly the call to 'getcurrentsession' is made, and when is it actually closed/committed?
You could look at the sources and use a debugger for this you know :) Look at HibernateTemplate, more precisely the doExecute() method, this is where the session is obtained. For the close/commit, look at the previously mentioned OpenSessionInViewFilter/Interceptor, both have methods for this purpose.
From what I understand, the spring framework has to handle the session lifecycle, where does it do this? at what point the in the requests lifecycle?
I think I covered that part: the session is created at the start of a request and closed at the end.
It is handling the Unit of work also, where/how?
I'm not sure to get this one. To me, Hibernate's Session is an implementation of the unit of work pattern. So this question is actually the same as the previous one.
PS: I provided some links that show that everything is actually clearly documented. Spring and Hibernate have extremely nice documentation and javadoc. Take advantage of that, look at them by yourself, look at the code by yourself, use your debugger, you'll learn a lot more.
Hibernate returns a custom implementation of the collection which does the loading only whenever any of the collection methods is been invoked. This collection has been constructed with the session as argument.
Do a sysout of getSomeCollection().getClass() to see which Hibernate custom class it is and check the appropriate javadocs/sourcecode to see how exactly they did it.
If you ever questioned the sense/use/value of interfaces and declaring against interfaces, now, this is a good example. You didn't see anything from it, did you? ;)
Is the session initialized and committed at a global level on a per request basis?
It's typically initialized on a per-request basis using ... (wait for it)
Please explain where exactly the call to 'getcurrentsession' is made, and when is it actually closed/committed?
It: org.springframework.orm.hibernate3.HibernateTemplate
... is the heart of Spring's integration with Hibernate. HibernateTemplate will initialize the session as necessary (or pull an already existing one from a ThreadLocal store) and provide it to any callbacks you give to the HibernateTemplate#execute* methods.
From what I understand, the spring framework has to handle the session lifecycle, where does it do this? at what point the in the requests lifecycle?
Also done by HibernateTemplate, and ...
It is handling the Unit of work also, where/how?
Done by HibernateTransactionManager, if you have one configured in your applicationContext.
If this was a web application I would use the OpenSessionInViewFilter