Hi,
I have two applications that are effectively services.
In order to conserve CPU I have EntityManagerFactory as a singleton, so it only gets called once.
In order to conserve CPU I have an EntityManager created per thread, in an EntityManagerController, in order to not hit the thread safety issue. In a multi-threaded application, each call to EntityManagerController.getInstance().getEntityManager() looks into a concurrent map using the thread as the key. If the returned em is null or not found a new em is created and stored in the concurrent map.
What I do, in order to conserve memory, is clear the persistent cache em.clear() after each commit.
When I run into a problem, primarily OptimisticLockException, I retry the LUW up to a set number of tries.
I did run into an issue which led me to clear the em after every commit. As, perhaps, a bug, I did not clear the em upon exception.
This reduced the frequency of errors to very rarely and virtually unreproducable.
I happened to find a URL off of hibernate (so it, presumably, is accurate) that stated if there is an exception, like OptimisticLockException,
I must close the em and create a new one. That the state of the em is unknown. This explains why in some cases, when I see this situation it tends to persist to other transactions.
My first question, is this a bug, that the em is not effectively idempotent? I also saw on that same URL that in a batch job once an error is received, the application must be terminated and restarted. My second question is, are you serious? Which is it, close and reopen the em or terminate the service? If it is terminate the service, I'll answer the first question for you, it IS a bug. It is not practical to terminate a 24x7 service upon an OptimisticLockException.
So, I guess my real question is could someone elaborate on the expected action when an OptimisticLockException occurs.
An important programming model to explain at this point is I do not use merge, as the persistent context is kept small, however, what I do to effect the same thing as DIY update/insert wherein I always do a find() on the PK. If the object returned is null (no object returned) I instantiate a new object and set the insert boolean to true. I then update the object attributes and, if insert==true, persist it.
Based on the documentation, when I do have an exception around a commit I attempt to rollback the transaction. But that logic is wrapper in the following:
Code:
if (em.isOpen && em.getTransaction().isAlive()) {
em.getTransaction().rollback();
}
The reason I mention this is these exceptions I receive seem to cascade
I receive a
javax.persistence.RollbackException caused by
javax.persistence.OptimisticLockException caused by
org.hibernate.StaleStateException
First, this strikes me as odd as I do catch the OptimisticLockException so I am perplexed as to why that chain of Exceptions isn't stopped at OptimisticLockException.
I would think that re executing the transaction, which forces a new find() on the objects being updated would work. This doesn't appear
to be the case. This, I believe, is where I could have, in the OptimisticLockException acquired the entity from the exception and done a merge on it. Is this essentially correct? However, if I must close the em (purging the persistent context, why bother?
As you fine folks can see, I am confused on this issue. Also in the confusion is the RollBackException due to having issued the rollback in the case of OptimisticLockException? It is my understanding from a hibernate URL on EntityManager one must rollback the transaction in the case of an exception.
So if someone could elaborate on what I really should expect and do here I would greatly appreciate it.
Thanks!
Walt