Spring 当存在外键时,事务同步器在事务结束前关闭 JPA 实体管理器
Spring transaction synchronizer closing JPA entity manager before end of transaction when foreign key present
我有一个使用 JTA 的 spring 应用程序(试过 atomikos 和 bitronix 都有同样的问题)+ JPA (Hibernate),我 运行 遇到以下问题
一切正常,直到我尝试使用外键(例如 OneToOne 关系,级联没有区别)。
当我这样做时,spring 事务同步器在事务完成之前强行关闭实体管理器,当事务管理器尝试提交时,我只得到:
ERROR: HHH000346: Error during managed flush [Session/EntityManager is closed]
没有其他日志表明 spring 提前关闭实体管理器的原因。
我发现如果我执行 entitymenager.flush(),就可以解决 大多数 情况下的问题,但不是全部。
我有一个单元测试项目重现了这个问题:https://github.com/Kloudtek/ktspring(单元测试是 standalone/atomikos-artemis-hibernate
这里是我正在使用的摘录
@Bean(initMethod = "init", destroyMethod = "shutdownForce")
public UserTransactionServiceImp userTransactionService() {
Properties p = new Properties();
p.setProperty("com.atomikos.icatch.service", "com.atomikos.icatch.standalone.UserTransactionServiceFactory");
p.setProperty("com.atomikos.icatch.default_jta_timeout","30000");
return new UserTransactionServiceImp(p);
}
@Bean(initMethod = "init", destroyMethod = "close")
@DependsOn("userTransactionService")
public UserTransactionManager UserTransactionManager() {
UserTransactionManager userTransactionManager = new UserTransactionManager();
userTransactionManager.setForceShutdown(false);
userTransactionManager.setStartupTransactionService(false);
return userTransactionManager;
}
@Bean
@DependsOn("userTransactionService")
public UserTransactionImp userTransactionImp() throws SystemException {
UserTransactionImp userTransactionImp = new UserTransactionImp();
return userTransactionImp;
}
@Bean
@DependsOn("userTransactionService")
public JtaTransactionManager jtaTransactionManager() {
return new JtaTransactionManager(UserTransactionManager(), UserTransactionManager());
}
@Bean
public JPAParams jpaParams() {
Properties p = new Properties();
p.setProperty("hibernate.connection.handling_mode", "DELAYED_ACQUISITION_AND_RELEASE_AFTER_TRANSACTION");
p.setProperty("hibernate.current_session_context_class", "jta");
p.setProperty("hibernate.transaction.jta.platform", AtomikosPlatform.class.getName());
return new JPAParams(p);
}
@Bean
public LocalContainerEntityManagerFactoryBean entityManager() {
LocalContainerEntityManagerFactoryBean entityManager = new LocalContainerEntityManagerFactoryBean();
if (config.isJtaDatasource()) {
entityManager.setJtaDataSource(config.getDataSource());
} else {
entityManager.setDataSource(config.getDataSource());
}
Properties p = new Properties();
p.putAll(config.getJpaProperties());
if (jpaParamsList != null) {
for (JPAParams jpaParams : jpaParamsList) {
p.putAll(jpaParams.getProperties());
}
}
entityManager.setJpaProperties(p);
entityManager.setPackagesToScan(config.getPackageToScan());
entityManager.setPersistenceProvider(new HibernatePersistenceProvider());
return entityManager;
}
@Entity
public class TestObj {
@Id
private int id;
@OneToOne
private TestObj2 testObj2;
public TestObj() {
}
public TestObj(int id) {
this.id = id;
}
public TestObj(int id, TestObj2 testObj2) {
this.id = id;
this.testObj2 = testObj2;
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
}
@Entity
public class TestObj2 {
@Id
private int id;
public TestObj2() {
}
public TestObj2(int id) {
this.id = id;
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
}
public void testDb() {
tx.execute(status -> {
entityManager.persist(new TestObj3(0));
TestObj2 o2 = new TestObj2(0);
entityManager.persist(o2);
TestObj o1 = new TestObj(0, o2);
entityManager.persist(o1);
// If i flush the problem disapears
// entityManager.flush();
return null;
});
}
我们在 spring 4.3.2 和 Hibernate 5.2.2 中遇到了类似的问题
将 hibernate 降级到 5.1.1 解决了我们的问题
我有一个使用 JTA 的 spring 应用程序(试过 atomikos 和 bitronix 都有同样的问题)+ JPA (Hibernate),我 运行 遇到以下问题
一切正常,直到我尝试使用外键(例如 OneToOne 关系,级联没有区别)。
当我这样做时,spring 事务同步器在事务完成之前强行关闭实体管理器,当事务管理器尝试提交时,我只得到:
ERROR: HHH000346: Error during managed flush [Session/EntityManager is closed]
没有其他日志表明 spring 提前关闭实体管理器的原因。
我发现如果我执行 entitymenager.flush(),就可以解决 大多数 情况下的问题,但不是全部。
我有一个单元测试项目重现了这个问题:https://github.com/Kloudtek/ktspring(单元测试是 standalone/atomikos-artemis-hibernate
这里是我正在使用的摘录
@Bean(initMethod = "init", destroyMethod = "shutdownForce")
public UserTransactionServiceImp userTransactionService() {
Properties p = new Properties();
p.setProperty("com.atomikos.icatch.service", "com.atomikos.icatch.standalone.UserTransactionServiceFactory");
p.setProperty("com.atomikos.icatch.default_jta_timeout","30000");
return new UserTransactionServiceImp(p);
}
@Bean(initMethod = "init", destroyMethod = "close")
@DependsOn("userTransactionService")
public UserTransactionManager UserTransactionManager() {
UserTransactionManager userTransactionManager = new UserTransactionManager();
userTransactionManager.setForceShutdown(false);
userTransactionManager.setStartupTransactionService(false);
return userTransactionManager;
}
@Bean
@DependsOn("userTransactionService")
public UserTransactionImp userTransactionImp() throws SystemException {
UserTransactionImp userTransactionImp = new UserTransactionImp();
return userTransactionImp;
}
@Bean
@DependsOn("userTransactionService")
public JtaTransactionManager jtaTransactionManager() {
return new JtaTransactionManager(UserTransactionManager(), UserTransactionManager());
}
@Bean
public JPAParams jpaParams() {
Properties p = new Properties();
p.setProperty("hibernate.connection.handling_mode", "DELAYED_ACQUISITION_AND_RELEASE_AFTER_TRANSACTION");
p.setProperty("hibernate.current_session_context_class", "jta");
p.setProperty("hibernate.transaction.jta.platform", AtomikosPlatform.class.getName());
return new JPAParams(p);
}
@Bean
public LocalContainerEntityManagerFactoryBean entityManager() {
LocalContainerEntityManagerFactoryBean entityManager = new LocalContainerEntityManagerFactoryBean();
if (config.isJtaDatasource()) {
entityManager.setJtaDataSource(config.getDataSource());
} else {
entityManager.setDataSource(config.getDataSource());
}
Properties p = new Properties();
p.putAll(config.getJpaProperties());
if (jpaParamsList != null) {
for (JPAParams jpaParams : jpaParamsList) {
p.putAll(jpaParams.getProperties());
}
}
entityManager.setJpaProperties(p);
entityManager.setPackagesToScan(config.getPackageToScan());
entityManager.setPersistenceProvider(new HibernatePersistenceProvider());
return entityManager;
}
@Entity
public class TestObj {
@Id
private int id;
@OneToOne
private TestObj2 testObj2;
public TestObj() {
}
public TestObj(int id) {
this.id = id;
}
public TestObj(int id, TestObj2 testObj2) {
this.id = id;
this.testObj2 = testObj2;
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
}
@Entity
public class TestObj2 {
@Id
private int id;
public TestObj2() {
}
public TestObj2(int id) {
this.id = id;
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
}
public void testDb() {
tx.execute(status -> {
entityManager.persist(new TestObj3(0));
TestObj2 o2 = new TestObj2(0);
entityManager.persist(o2);
TestObj o1 = new TestObj(0, o2);
entityManager.persist(o1);
// If i flush the problem disapears
// entityManager.flush();
return null;
});
}
我们在 spring 4.3.2 和 Hibernate 5.2.2 中遇到了类似的问题 将 hibernate 降级到 5.1.1 解决了我们的问题