views:

29

answers:

2

I need some clarification on the right way to retry a "retryable" exception (e.g. something like lock wait timeout) when using java persistence. For example, with pseudocode like:

EntityTransaction tx = em.getTransaction();
tx.begin();
for (a bunch of objects) {
  em.persist(object);
}
tx.commit();

I sometimes get an exception thrown at the em.persist call if there's a lock in the db. Can I just wrap that in a try/catch and retry it (with some count, obviously)? Or do I have to wrap the whole tx.begin/commit and redo that?

thx

A: 

If you are programming to the spec, you are actually supposed to dispose the entire EntityManager and start over. There are no exceptions that are guaranteed to be 'retryable' at the EM level. Your entire persistence session is considered inconsistent/indeterminate if an exception comes out of the persist() method.

Sometimes it will work. I know in hibernate you can usually get away with trying gain after an optimistic lock exception. But in general, you are relying on vendor specific behavior that may be poorly defined if you try to catch and recover from entitymanager exceptions and keep the same entitymanager.

More info here.

Affe
+1  A: 

Assuming that the lock timeouts are not there as a workaround for database deadlocks, a simpler solution would be to just use longer time-outs on your requests. Instead of using an N second timeout and retrying up to C times, set the timeout to N * (C + 1) seconds.

(If you are using the lock timeouts as a workaround for deadlocks, then you have a bigger problem. You'd do better to try to fix the root cause of the deadlocks, because even with C retries there is a probability that your transactions won't go through.)

Stephen C