Hello,
I have been battling with optimistic locks in hibernate for the past couple of days and seem to be going round in circles. If anybody could point me in the right direction with this it would be much appreciated.
Basically my application uses optimistic locking on some object using the @Version annotation. This seems to be all working fine. However, I would like to retry the transaction if it fails due to the lock i.e. another user has updated the object - retry.
This area seems to be somewhat lacking in the documentation for either Spring or Hibernate but I have come to the conclusion that I should make an AOP aspect to run on a custom annotation (e.g. @RetriableTransaction). (I am also using spring's @Transactional which has meant that I had to adjust the precedence of that advice so my advice runs above @Transactional - is this advisable?)
At first this seems to be work correctly - however...when I force a Optimistic lock failure (modify the version number in the database while the application is paused) things start to fall apart. It does appear to complete the retry successfully but other persistent objects in the application start to fail with LazyInit Exception or session not open. It appears that once the Optimistic lock exeption has been thrown the session becomes null.
After some more reading it is suggested that all Hibernate Exceptions are non-recoverable? If this is the case how do I achieve a retry?
I am convinced I am doing something wrong as this functionality is surely fairly basic for any scalable enterprise system? i.e. transactions which are able to be re-applied shouldn't ever fall back to the user
Any advice or suggestions are most welcome.
Retry Advice method
Service Layer annotated method (User and Role objects have a version field annotated with @Version)Code:@Around("@annotation(RetriableTransaction)") public Object retry(ProceedingJoinPoint pjp) throws Throwable { boolean success=false; int tries=0; Object o=null; while(!success) { try { o=pjp.proceed(); success=true; } catch (HibernateOptimisticLockingFailureException e) { System.err.println("Collision - optlock"); tries++; if (tries>=maxRetries) throw e; } catch (StaleStateException se) { System.err.println("Collision - stalestate"); tries++; if (tries>=maxRetries) throw se; } } return o; }
Another non-transactional service layer methodCode:@RetriableTransaction @Transactional public User addRoleToUser(User user, Role role) { dao.refresh(user); dao.refresh(role); user.addRole(role); role.addUser(user); dao.save(role); dao.save(user); return user; }
Code:public void anotherServiceLayerMethod() { MyPersistentObject o=(MyPersistentObject)dao.load(MyPersistentObject.class, new Long(1)); User u=userService.getUserById(new Long(1)); Role r=userService.getRoleById(new Long(2)); u=userService.addRoleToUser(u, r); o.getMyCollection(); //<--EXCEPTION thrown here (LazyInitializationException) }


Reply With Quote
