Announcement Announcement Module
Collapse
No announcement yet.
How does one retry a (JPA) transaction if optimistic locking failed? Page Title Module
Move Remove Collapse
X
Conversation Detail Module
Collapse
  • Filter
  • Time
  • Show
Clear All
new posts

  • How does one retry a (JPA) transaction if optimistic locking failed?

    HI,

    I'm using spring-data-jpa in combination with Hibernate 4 for data access. I provide a web service that gets hit quite frequent and the basic usage scenario results in a high count of object insertions. My data model is somewhat hierarchical and updates tend to "bubble up" the tree. If the load is high enough this will lead to either database deadlocks or optimistic locking failures. I know why this errors occur and I think I have reached a point where I simply have to accept that some transactions my have to be retried if they fail.

    I had a look but it seems that spring doesn't support this use case without further manual work on my side. A lot of people seem to suggest wiring up method interceptors that simply run the respective methods again if a defined exception does happen. This might work in general but I fear in the light of JPA/Hibernate this simple approach may not suffice. I think that for a given method to fail deterministically one would have to force a transaction commit or session flush or else the flush may happen somewhere later on the code path where a transaction is no longer retry-able. I further think that one has to rollback the transactions that failed and therefor needs a way to start a fresh transaction before retrying some given method. I'm just not entirely sure in this regard. My main problem is that the methods I would like to try again after a failure usually reside deep in a callstack of multiple @Transactional methods. Usually the flow is something like this: @Controller -> @Service -> @Service (here I want to retry) -> @Repository.

    Despite my regards I went forward implementing my own version of the method interceptor that one can find on the first few google hits for "spring retry transaction". Please have a look:

    RetryingTransaction.java
    RetryingTransactionAspect.java

    It looks like this could work. My main problem is that the result value of the given joinpoint my be a JPA entity and due to the nested transaction this entity ends up as a detached entity in the original transaction. So if some action further up the call chain results in lazy loading the usual Hibernate Exception occurs where I'm told that there is no open session in the thread but of course there is just the given entity is not part of the session as it's session has already been flushed. I can't just go with injecting the entity manager and merging the return value of the joinpoint because it may not be a JPA entity or it may be null or the JPA entity might have been wrapped in some kind of result object that is no entity in itself.

    So my question is whether I'm wrong and no manual transaction handling has to be done in my method interceptor. Or if I'm right then how would one go about merging arbitrary result values into the current Hibernate session?
Working...
X