【问题标题】:Why JPA/Hibernate transaction is active even when I did not start one explicitly为什么即使我没有明确启动 JPA/Hibernate 事务也是活动的
【发布时间】:2017-04-24 22:33:23
【问题描述】:

我的问题是 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 方法,但我想了解为什么存在事务。感谢您的帮助!

【问题讨论】:

    标签: java hibernate jpa transactions


    【解决方案1】:

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

    Transaction txn = entityManager.getTransaction();
    
    if (txn.isActive()) {
       try {
         txn.rollback();
         } catch (PersistenceException | IllegalStateException e) {
            LOG.error("Transaction rollback failed.", e);
          }
    }
    

    【讨论】:

    • 感谢您提示调用 entityManager.getTransaction() 已经开始交易,即使您的回答不能直接解决我的问题,因为我根本不想要交易对象。
    • 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. 这是一个糟糕的建议。见codota.com/code/java/methods/org.hibernate.Transaction/isActivesession.getTransaction().begin(); ... session.getTransaction().commit();
    【解决方案2】:

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

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

    这将阻止 EntityManagerCloser 启动自己的事务,我以后无法回滚,因为我没有显式调用 transaction.begin()

    【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2020-02-05
    • 2014-09-03
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-05-09
    • 1970-01-01
    相关资源
    最近更新 更多