From the Hibernate 2.1.2 manual:
Quote:
Don't treat exceptions as recoverable.
This is more of a necessary paractice than a "best" practice. When an exception occurs, roll back the Transaction and close the Session. If you don't, Hibernate can't guarantee that in-memory state accurately represents persistent state. As a special case of this, do not use Session.load() to determine if an instance with the given identifier exists on the database; use find() instead.
I'm pretty sure that would apply to retrying transaction commits.
What you might want to think about is a command design pattern.
Instead of munging your transaction handling and domain model manipulation into one big procedural chunk, use the command/decorator patterns to do something like this:
Define an interface the represents actions that can be retried:
Code:
public interface RetryableAction {
void try(Session session) throws HibernateException;
}
Then have an object responsible for executing retryable actions:
Code:
public class Executor {
public static void execute(RetryableAction action) throw HibernateException {
// get new HB Session
// begin TX
try {
action.try(session);
// commit TX
}
catch( HibernateException he ){
// rollback TX
// close & discard HB Session
if( wadDeadlockError(he) ){
// wait a random amount of time
// get new HB Session
action.try(session);
// commit TX
// close & discard HB Session
}
}
Then you'd just write code like this:
Code:
RetryableAction doSomething = new RetryableAction() {
public void tryAction(Session session){
// do some domain model stuff
}
}
Executor.execute(doSomething);
Wouldn't something like this be heaps better than sprinkling retry code throughout your app?
Of course, I've not tried that approach before and I just made that example up.
If you did try this, I'd put some more thought into it that I have. Also, if you do do this and it works, add a page to the wiki that explains the details so other people can benefit from your experience.