Hibernate 5.2.x“事务已激活”奇怪的行为

时间:2018-11-02 11:31:36

标签: java hibernate jpa transactions jta

从Hibernate 4.x迁移到最新的Hibernate 5版本时,我在事务管理方面遇到了问题。

在我的代码中,有一个事务管理器开始JTA事务,然后调用Session.beginTransaction。下面是重现该问题的示例(该方案未使用Spring或任何其他容器管理的事务管理):

transactionManager.begin();
saveOrUpdate(entity1);
saveOrUpdate(entity2);
...
transactionManager.commit();

private void saveOrUpdate(SomeEntity entity) {
    try (Session session = sessionFactory.openSession()) {
        session.setFlushMode(FlushMode.AUTO);
        session.beginTransaction();   // throws IllegalStateException "Transaction already active"
        try {
            session.saveOrUpdate(entity);
            session.getTransaction().commit();
        } catch (Exception ex) {
            session.getTransaction().rollback();
            throw RuntimeException(ex);
        }
    }
}

这导致 IllegalStateException与消息"Transaction already active" 一起抛出。这种行为似乎已在Hibernate 5.2.0(this is the commit)中引入。 以前,Hibernate忽略了物理事务本身的开始,因为它知道存在封闭的事务:它只是创建JtaTransaction且将isInitiator设置为false的包装器。

此异常在org.hibernate.engine.transaction.internal.TransactionImpl中引发,特别是在begin()方法中:

@Override
public void begin() {
    if ( !session.isOpen() ) {
        throw new IllegalStateException( "Cannot begin Transaction on closed Session/EntityManager" );
    }

    if ( transactionDriverControl == null ) {
        transactionDriverControl = transactionCoordinator.getTransactionDriverControl();
    }

    // per-JPA
    if ( isActive() ) {   // *** This is the problematic part *** //
        throw new IllegalStateException( "Transaction already active" );
    }

    LOG.debug( "begin" );

    this.transactionDriverControl.begin();
}

这也与user manual相抵触,其中的内容如下:

// Note: depending on the JtaPlatform used and some optional settings,
// the underlying transactions here will be controlled through either
// the JTA TransactionManager or UserTransaction

Session session = sessionFactory.openSession();
try {
    // Assuming a JTA transaction is not already active,
    // this call the TM/UT begin method.  If a JTA
    // transaction is already active, we remember that
    // the Transaction associated with the Session did
    // not "initiate" the JTA transaction and will later
    // nop-op the commit and rollback calls...
    session.getTransaction().begin();

这是Hibernate中的错误吗? “按JPA”注释在引发异常的代码中到底意味着什么?有办法恢复旧的行为吗?

2 个答案:

答案 0 :(得分:1)

行为符合预期,好:您在transactionmanager处开始了一笔交易。 我认为它正在按照JTA运行。因此,您收到的针对openSession的连接应该会参与已经开始交易的transactionmanagers。

开始其他事务必须导致此异常。

答案 1 :(得分:0)

这实际上是我在https://hibernate.atlassian.net/browse/HHH-13076中报告的“回归”,现已修复(here's the PR link)。