In your "My code" snippet, there might be some problems:
- In case of an exception, there is no
finally
block to close the session
- You are calling
session.close()
, but this is different from HibernateUtils.closeSession()
. So the ThreadLocal
is not cleared.
- There is no
catch
block for exceptions; as a consequence there is no rollback
.
- Do you rethrow exceptions or are they (silently) ignored?
If there is an exception in the "to do" block after begin()
, the transaction remains open, and ThreadLocal
is not cleared.
Your code may work fine normally, but under high load there might be (SQL lock) timeouts etc., and in this case, once in a while, an exception will be thrown.
So check each snippet for correct exception handling:
final Session session = HibernateUtil.getSession();
try {
final Transaction transaction = session.beginTransaction();
try {
// The real work is here
transaction.commit();
} catch (Exception ex) {
// Log the exception here
transaction.rollback();
throw ex;
}
} finally {
HibernatilUtil.closeSession();
}
You could add some "book-keeping" code to HibernateUtil.getSession()
and HibernateUtil.closeSession()
: Log each access, including the thread's name. Eventually one or multiple "gets" by the same thread must be followed by a "close".
In your case I would even consider to have only one "get", and pass the session around as long as your thread is doing its unit of work: This way it's possibly easier to find the problem.
There is another question on SO which reports a similar problem: Hibernate 4.1.9 (latest final build) reporting `nested transactions not supported.
You could add some code after commit()
to check, if the transaction has been really completed (by calling wasCommitted()
).
A quote from the Javadoc of wasCommitted()
:
This method could return false even after successful invocation of commit(). As an example, JTA based strategies no-op on commit() calls if they did not start the transaction; in that case, they also report wasCommitted() as false.
与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…