当前位置: 首页 > 知识库问答 >
问题:

为什么JPA/Hibernate事务在我没有明确启动的情况下仍处于活动状态

后化
2023-03-14

我的问题是JPA/Hibernate在调用entityManager时返回true。getTransaction()。isActive(),即使我没有显式启动事务(请参阅下面的代码)。

这里的问题是,我想从数据库中读取一些内容,在这种情况下,SerializationException是可以的,因为这只是表明持久化对象不再适合实际代码,需要重新计算。下面的代码不只是返回null,而是引发以下异常:

Transaction rollback failed.
org.hibernate.TransactionException: Unable to rollback against JDBC Connection

这向我表明,一定有一个我在代码中没有启动的事务。上面代码中的最后一个块是

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方法,但我想了解为什么会有事务。谢谢你的帮助!

共有2个答案

梁巴英
2023-03-14

多亏了Jobin,我很快找到了解决问题的方法:

我想我需要调用entityManager.isJoinedToTransaction()在我的CloseEntityManager方法之前调用entityManager.getTransaction(). isActive()

这将防止EntityManagerCston启动它自己的事务,我以后不能回滚,因为我没有显式调用transaction.begin()

杨宏儒
2023-03-14

问题是,当您调用entityManager时。getTransaction() 将创建一个新的事务对象。因此,最好将事务引用保存到变量,如下所示。

Transaction txn = entityManager.getTransaction();

if (txn.isActive()) {
   try {
     txn.rollback();
     } catch (PersistenceException | IllegalStateException e) {
        LOG.error("Transaction rollback failed.", e);
      }
}
 类似资料: