在使用Spring 4.3.18时,我一直在将项目升级到Hibernate 5.4.2.Final。除了我在一项集成测试中收到的例外情况外,大多数事情都成功了。执行删除操作时,将引发异常。删除是列表中要迭代的几个对象之一。前8个成功,但第9个我收到以下异常:
org.springframework.dao.InvalidDataAccessApiUsageException:执行更新/删除查询;嵌套的异常是javax.persistence.TransactionRequiredException:执行更新/删除查询
我已经遍历了代码,可以看到我处于活动事务中,至少Spring正在报告,但是EntityManager报告它未加入事务。
我的EntityManager在Spring中的接线方式如下:
<bean id="entityManagerFactory" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean" primary="true">
<property name="dataSource" ref="dataSource"/>
<property name="jpaVendorAdapter">
<bean class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter">
<property name="showSql" value="false" />
<property name="databasePlatform" value="org.hibernate.dialect.MySQL55Dialect" />
</bean>
</property>
<property name="jpaPropertyMap">
<props>
<prop key="hibernate.transaction.factory_class">org.springframework.orm.hibernate5.HibernateTransactionManager</prop>
</props>
</property>
</bean>
persistence.xml文件如下:
<persistence-unit name="myPersistenceUnit" transaction-type="RESOURCE_LOCAL">
<provider>org.hibernate.ejb.HibernatePersistence</provider>
<properties>
<property name="hibernate.dialect" value="org.hibernate.dialect.MySQL55Dialect"/>
<property name="hibernate.dialect.storage_engine=" value="innodb" />
<property name="hibernate.hbm2ddl.auto" value=""/>
<property name="hibernate.use_sql_comments" value="true"/>
<!-- Implicit Naming Strategy ensures that table & column names are genereated as expected -->
<property name="hibernate.implicit_naming_strategy" value="common.hibernate.model.naming.ImplicitNamingStrategy"/>
</properties>
</persistence-unit>
在应用程序启动期间没有错误,但是有一些来自Hibernate的INFO和DEBUG消息:
2019-04-18 10:23:07,770 [main sessionId: vaultId: userId: origReqUri:] INFO org.hibernate.validator.internal.util.Version - HV000001: Hibernate Validator 6.0.14.Final
2019-04-18 10:23:09,559 [main sessionId: vaultId: userId: origReqUri:] DEBUG org.hibernate.engine.transaction.jta.platform.internal.JtaPlatformInitiator - No JtaPlatform was specified, checking resolver
2019-04-18 10:23:09,560 [main sessionId: vaultId: userId: origReqUri:] DEBUG org.hibernate.engine.transaction.jta.platform.internal.JtaPlatformResolverInitiator - No JtaPlatformResolver was specified, using default [org.hibernate.engine.transaction.jta.platform.internal. StandardJtaPlatformResolver]
2019-04-18 10:23:09,581 [main sessionId: vaultId: userId: origReqUri:] DEBUG org.hibernate.engine.transaction.jta.platform.internal.StandardJtaPlatformResolver - Could not resolve JtaPlatform, using default [org.hibernate.engine.transaction.jta.platform.internal.NoJtaPlatform]
2019-04-18 10:23:09,581 [main sessionId: vaultId: userId: origReqUri:] INFO org.hibernate.engine.transaction.jta.platform.internal.JtaPlatformInitiator - HHH000490: Using JtaPlatform implementation: [org.hibernate.engine.transaction.jta.platform.internal.NoJtaPlatform]
2019-04-18 10:23:09,803 [main sessionId: vaultId: userId: origReqUri:] INFO org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean - Initialized JPA EntityManagerFactory for persistence unit 'default'
我根本无法确定EntityManager为什么在Spring中有活动时显示没有事务的原因。我假设我可能缺少某种配置,但是我无法确定是什么。
任何帮助将不胜感激。 谢谢...
经过进一步调查,似乎这是由LogicalConnectionManagedImpl#afterCompletion()方法引起的,该方法又在AbstractLogicalConnectionImplementor#resetConnection()方法中调用了resetConnection()的超类实现。
protected void afterCompletion() {
resetConnection( initiallyAutoCommit );
initiallyAutoCommit = false;
afterTransaction();
}
在resetConnection()中,连接状态设置为NOT_ACTIVE:
protected void resetConnection(boolean initiallyAutoCommit) {
try {
if ( initiallyAutoCommit ) {
log.trace( "re-enabling auto-commit on JDBC Connection after completion of JDBC-based transaction" );
getConnectionForTransactionManagement().setAutoCommit( true );
status = TransactionStatus.NOT_ACTIVE;
}
}
catch ( Exception e ) {
log.debug("Could not re-enable auto-commit on JDBC Connection after completion of JDBC-based transaction : " + e);
}
}
这将导致EntityManager报告它未加入事务,即使Spring正在管理一个活动事务。这会导致此时所做的任何更新语句都失败,因为Hibernate认为没有活动的事务。
在我的persistence.xml文件中可以提供一个标志:
hibernate.allow_update_outside_transaction = true
但这对我来说似乎很危险,因为JPA规范出于充分的理由禁止这种行为。
Hibernate的resetConnection()方法中的这一更改显然是导致问题的原因,但我无法确定为什么现在要调用它。 Spring仍然相信有活跃的交易。当我的SQL工作在afterCommit同步中执行时,由于事务仍处于活动状态,因此实际上应该没有问题。
除了使用persistence.xml中的属性之外,还有其他方法可以解决此问题吗?