Hibernate 5.2.x "Транзакция уже активна", странное поведение - PullRequest
0 голосов
/ 02 ноября 2018

При переходе с 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 ( это коммит ). Ранее 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();
}

Это также противоречит руководству пользователя , где говорится следующее:

// 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 голосов
/ 19 ноября 2018

На самом деле это была «регрессия», о которой я сообщил в https://hibernate.atlassian.net/browse/HHH-13076, которая теперь исправлена ​​( вот PR-ссылка ).

0 голосов
/ 03 ноября 2018

Поведение соответствует ожидаемому, хорошо: вы начали транзакцию в диспетчере транзакций. Я предполагаю, что это работает в соответствии с JTA. Поэтому ожидается, что полученное вами соединение для openSession будет участвовать в уже запущенной транзакции менеджера транзакций.

Запуск дополнительной транзакции должен привести к этому исключению.

...