休眠 5.2.x "Transaction already active" 奇怪的行为
Hibernate 5.2.x "Transaction already active" weird behavior
从 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 中的错误吗? "per-JPA" 注释在抛出异常的代码中究竟意味着什么?有没有办法恢复旧的行为?
行为符合预期:您在事务管理器中开始了事务。
我认为它正在根据 JTA 工作。因此,您收到的 openSession 连接预计会参与 transactionmanagers 已经开始的事务。
开始额外的事务必须导致此异常。
这实际上是我在 https://hibernate.atlassian.net/browse/HHH-13076 which is now fixed (here's the PR link 中报告的 "regression"。
从 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 中的错误吗? "per-JPA" 注释在抛出异常的代码中究竟意味着什么?有没有办法恢复旧的行为?
行为符合预期:您在事务管理器中开始了事务。 我认为它正在根据 JTA 工作。因此,您收到的 openSession 连接预计会参与 transactionmanagers 已经开始的事务。
开始额外的事务必须导致此异常。
这实际上是我在 https://hibernate.atlassian.net/browse/HHH-13076 which is now fixed (here's the PR link 中报告的 "regression"。