我的问题是JPA / Hibernate为 entityManager.getTransaction()。isActive()的调用返回 true ,即使我没有显式启动事务(参见代码如下)。
这里的问题是我想从数据库中读取一些东西,并且在这种情况下SerializationException是可以的,因为这只是表明持久化对象不再适合实际代码,需要重新计算。下面的代码不是仅返回null,而是抛出以下异常:
Transaction rollback failed.
org.hibernate.TransactionException: Unable to rollback against JDBC Connection
这告诉我,我的代码中一定有一个我没有启动的事务。上面代码中的finally块是
final EntityManager entityManager = Persistence.createEntityManagerFactory("test").createEntityManager();
try {
final TypedQuery<Test> query = entityManager.createQuery("SELECT t FROM test t", Test.class);
return query.getResultList();
} catch (final PersistenceException e) {
if (e.getCause() instanceof SerializationException) {
LOG.debug("Implementation changed meanwhile. That's ok - we return null.");
return null;
}
throw e;
} finally {
EntityManagerCloser.closeEntityManager(entityManager);
}
EntityManagerCloser看起来像这样:
public final class EntityManagerCloser {
private static final Logger LOG = LoggerFactory.getLogger(EntityManagerCloser.class);
public static void closeEntityManager(EntityManager entityManager) {
if (entityManager.getTransaction().isActive()) {
try {
entityManager.getTransaction().rollback();
} catch (PersistenceException | IllegalStateException e) {
LOG.error("Transaction rollback failed.", e);
}
}
if (entityManager.isOpen()) {
try {
entityManager.close();
} catch (IllegalStateException e) {
LOG.error("Closing entity manager failed.", e);
}
}
}
}
Hibernate docs说“始终使用明确的事务边界,即使是只读操作”。所以我真的需要插入一个
entityManager.getTransaction().begin();
....
<do read here>
....
entityManager.getTransaction().commit();
围绕我在数据库上执行的每个读操作?
我可以在没有回滚事务块的情况下为只读操作实现另一个closeEntityManager方法,但我想了解为什么有一个事务。谢谢你的帮助!
答案 0 :(得分:2)
The problem is that when you call entityManager.getTransaction();
a new transaction object will be created. So it is better to save the transaction reference to a variable as shown below.
Transaction txn = entityManager.getTransaction();
if (txn.isActive()) {
try {
txn.rollback();
} catch (PersistenceException | IllegalStateException e) {
LOG.error("Transaction rollback failed.", e);
}
}
答案 1 :(得分:0)
Thanks to Jobin I quickly found the solution to my problem:
I think I need to call entityManager.isJoinedToTransaction()
in my closeEntityManager method before calling entityManager.getTransaction().isActive()
.
This will prevent the EntityManagerCloser to start its own transaction which I can not rollback later because I did not explicitly call transaction.begin()
on it.