Java 切换到JPA,现在我总是在任何插入上获得TransactionRequiredException
我有一个Spring4Web应用程序。最初我使用HibernateJava 切换到JPA,现在我总是在任何插入上获得TransactionRequiredException,java,spring,hibernate,jpa,transactions,Java,Spring,Hibernate,Jpa,Transactions,我有一个Spring4Web应用程序。最初我使用HibernateSessionFactory,并使用Spring Hibernate API进行开发。一切都很顺利。也许我最近愚蠢地决定改用JPA,而Hibernate仍然是我的提供者。我重新配置了Spring设置并重写了大部分代码。最初,测试了一个数据库,以便我所有的数据库读取都能正常工作。然后我尝试了数据库写入,但都失败了,就像这样: javax.persistence.TransactionRequiredException: no tra
SessionFactory
,并使用Spring Hibernate API进行开发。一切都很顺利。也许我最近愚蠢地决定改用JPA,而Hibernate仍然是我的提供者。我重新配置了Spring设置并重写了大部分代码。最初,测试了一个数据库,以便我所有的数据库读取都能正常工作。然后我尝试了数据库写入,但都失败了,就像这样:
javax.persistence.TransactionRequiredException: no transaction is in progress
at org.hibernate.ejb.AbstractEntityManagerImpl.flush(AbstractEntityManagerImpl.java:970)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:483)
at org.springframework.orm.jpa.ExtendedEntityManagerCreator$ExtendedEntityManagerInvocationHandler.invoke(ExtendedEntityManagerCreator.java:342)
at com.sun.proxy.$Proxy47.flush(Unknown Source)
at com.taubler.oversite.dao.impl.EntityDaoImpl.insert(EntityDaoImpl.java:65)
...
请记住,当使用HibernateTemplate
、SessionFactory
、HibernateTransactionManager
等时,我的代码工作得很好。我的业务逻辑类以及DAO都像以前一样使用@Transactional
进行了注释
Hibernate似乎正在尝试创建事务,正如我在堆栈跟踪之前的日志中看到的:
2014-09-24 05:40:28 [http-bio-8080-exec-3] DEBUG org.hibernate.engine.transaction.internal.jdbc.JdbcTransaction - initial autocommit status: true
2014-09-24 05:40:28 [http-bio-8080-exec-3] DEBUG org.hibernate.engine.transaction.internal.jdbc.JdbcTransaction - disabling autocommit
2014-09-24 05:40:28 [http-bio-8080-exec-3] DEBUG org.hibernate.internal.SessionImpl - Opened session at timestamp: 14115372286
2014-09-24 05:40:28 [http-bio-8080-exec-3] TRACE org.hibernate.internal.SessionImpl - Setting flush mode to: AUTO
2014-09-24 05:40:28 [http-bio-8080-exec-3] TRACE org.hibernate.internal.SessionImpl - Setting cache mode to: NORMAL
2014-09-24 05:40:28 [http-bio-8080-exec-3] TRACE org.hibernate.event.internal.AbstractSaveEventListener - Transient instance of: com.taubler.oversite.entities.EmailAddress
2014-09-24 05:40:28 [http-bio-8080-exec-3] TRACE org.hibernate.event.internal.DefaultPersistEventListener - Saving transient instance
2014-09-24 05:40:28 [http-bio-8080-exec-3] TRACE org.hibernate.event.internal.AbstractSaveEventListener - Saving [com.taubler.oversite.entities.EmailAddress#<null>]
2014-09-24 05:40:28 [http-bio-8080-exec-3] TRACE org.hibernate.engine.spi.IdentifierValue - ID unsaved-value: null
2014-09-24 05:40:28 [http-bio-8080-exec-3] DEBUG org.hibernate.event.internal.AbstractSaveEventListener - Delaying identity-insert due to no transaction in progress
2014-09-24 05:40:28 [http-bio-8080-exec-3] DEBUG org.hibernate.internal.SessionImpl - Opened session at timestamp: 14115372287
2014-09-24 05:40:28 [http-bio-8080-exec-3] TRACE org.hibernate.internal.SessionImpl - Setting flush mode to: AUTO
2014-09-24 05:40:28 [http-bio-8080-exec-3] TRACE org.hibernate.internal.SessionImpl - Setting cache mode to: NORMAL
2014-09-24 05:40:28 [http-bio-8080-exec-3] DEBUG org.hibernate.engine.transaction.spi.AbstractTransactionImpl - rolling back
2014-09-24 05:40:28 [http-bio-8080-exec-3] DEBUG org.hibernate.engine.transaction.internal.jdbc.JdbcTransaction - rolled JDBC Connection
2014-09-24 05:40:28 [http-bio-8080-exec-3] DEBUG org.hibernate.engine.transaction.internal.jdbc.JdbcTransaction - re-enabling autocommit
2014-09-24 05:40:28 [http-bio-8080-exec-3] TRACE org.hibernate.engine.transaction.internal.TransactionCoordinatorImpl - after transaction completion
2014-09-24 05:40:28 [http-bio-8080-exec-3] TRACE org.hibernate.internal.SessionImpl - after transaction completion
2014-09-24 05:40:28 [http-bio-8080-exec-3] TRACE org.hibernate.internal.SessionImpl - Closing session
2014-09-24 05:40:28 [http-bio-8080-exec-3] TRACE org.hibernate.engine.jdbc.internal.LogicalConnectionImpl - Closing logical connection
2014-09-24 05:40:28 [http-bio-8080-exec-3] TRACE org.hibernate.engine.jdbc.internal.JdbcResourceRegistryImpl - Closing JDBC container [org.hibernate.engine.jdbc.internal.JdbcResourceRegistryImpl@2c4e3947]
2014-09-24 05:40:28 [http-bio-8080-exec-3] DEBUG org.hibernate.engine.jdbc.internal.LogicalConnectionImpl - Releasing JDBC connection
2014-09-24 05:40:28 [http-bio-8080-exec-3] DEBUG org.hibernate.engine.jdbc.internal.LogicalConnectionImpl - Released JDBC connection
2014-09-24 05:40:28 [http-bio-8080-exec-3] TRACE org.hibernate.engine.jdbc.internal.LogicalConnectionImpl - Logical connection closed
那个经理叫道:
...
@PersistenceUnit
private EntityManagerFactory entityManagerFactory;
protected final EntityManager getEntityManager() {
return entityManagerFactory.createEntityManager();
}
public boolean insert(Entity o) {
o.setCreated(new Date());
this.getEntityManager().persist(o);
this.getEntityManager().flush();
return true;
}
我试过不同的版本。最初,DAO和Manager方法都用@Transactional(propagation=REQUIRED)注释代码>这就是纯Hibernate的工作方式。我已经尝试删除传播设置,只注释管理器方法,只注释DAO方法。。。什么都不管用
有什么想法吗?HibernateTransactionManager
和JpaTransactionManager
之间似乎有着本质的不同
@PersistenceUnit
private EntityManagerFactory entityManagerFactory;
protected final EntityManager getEntityManager() {
return entityManagerFactory.createEntityManager();
}
问题是您自己正在创建实体管理器,不要。只需插入EntityManager
而不是EntityManager工厂
,并用@PersistenceContext
而不是@PersistenceUnit
进行注释。Spring将负责将其绑定到当前事务
@PersistenceContext
private EntityManager entityManager;
protected final EntityManager getEntityManager() {
return entityManger;
}
如果确实希望继续注入EntityManager工厂
,请使用EntityManager工厂utils
的getTransactionalEntityManager
方法来获取Spring managedEntityManager
实例
protected final EntityManager getEntityManager() {
return EntityManagerFactoryUtils.getTransactionalEntityManager(entityManagerFactory);
}
另外,它与“普通”hibernate一起工作并不意味着你的设置必须正确。您提到您使用了HibernateTemplate
,它基本上可以在没有正确事务设置的情况下工作,因为它只会为手头的操作启动一个新的事务。因此,很可能是应用程序在实际无法正常工作的地方似乎正常工作。可能您有多个事务(来自服务层)
另一个注意事项是,您的代码可能很危险
public boolean insert(Entity o) {
o.setCreated(new Date());
this.getEntityManager().persist(o);
this.getEntityManager().flush();
return true;
}
在您的情况下,这可能会导致创建两个不同的EntityManager
s,因此您可能在持久化时刷新了另一个。接下来,您不应该调用flush
,因为这将在事务结束时完成
问题是您自己正在创建实体管理器,不要。只需插入EntityManager
而不是EntityManager工厂
,并用@PersistenceContext
而不是@PersistenceUnit
进行注释。Spring将负责将其绑定到当前事务
@PersistenceContext
private EntityManager entityManager;
protected final EntityManager getEntityManager() {
return entityManger;
}
如果确实希望继续注入EntityManager工厂
,请使用EntityManager工厂utils
的getTransactionalEntityManager
方法来获取Spring managedEntityManager
实例
protected final EntityManager getEntityManager() {
return EntityManagerFactoryUtils.getTransactionalEntityManager(entityManagerFactory);
}
另外,它与“普通”hibernate一起工作并不意味着你的设置必须正确。您提到您使用了HibernateTemplate
,它基本上可以在没有正确事务设置的情况下工作,因为它只会为手头的操作启动一个新的事务。因此,很可能是应用程序在实际无法正常工作的地方似乎正常工作。可能您有多个事务(来自服务层)
另一个注意事项是,您的代码可能很危险
public boolean insert(Entity o) {
o.setCreated(new Date());
this.getEntityManager().persist(o);
this.getEntityManager().flush();
return true;
}
在您的情况下,这可能会导致创建两个不同的EntityManager
s,因此您可能在持久化时刷新了另一个。其次,您不应该调用flush
,因为这将在事务结束时完成。您需要使用@PersistenceContext
注释直接注入EntityManager
,您需要用@PersistenceContext
注释直接插入EntityManager
而不是PersistenceUnit,而不是PersistenceUnit
;谢谢我没有意识到我每次都在创建一个新的EntityManager,但现在这是非常有意义的。另外,HibernateTemplate工作并不是“正确”设置的证明。尽管嵌套的事务性方法应该非常好,尤其是在propagation=REQUIRED的情况下,并且只会产生一个事务。我确实读过,Spring事务传播与JPA事务管理器的行为不同;谢谢我没有意识到我每次都在创建一个新的EntityManager,但现在这是非常有意义的。另外,HibernateTemplate工作并不是“正确”设置的证明。尽管嵌套的事务性方法应该非常好,尤其是在propagation=REQUIRED的情况下,并且只会产生一个事务。我确实读过,Spring事务传播与JPA事务管理器的行为不同。