我有一個Spring4的Web應用程序。最初我使用Hibernate SessionFactory
,並使用Spring Hibernate API進行開發。一切正常。可能愚蠢地,我最近決定改用JPA,而Hibernate仍然是我的提供者。我重新配置了我的Spring設置並重寫了我的大部分代碼。最初進行了測試,以便我所有的數據庫讀取都能夠正常工作。然後我試圖寫入數據庫,他們都未能像這樣:切換到JPA,現在我總是得到任何插入TransactionRequiredException
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
註解。
看起來好像休眠試圖創建一個交易,因爲我看到在我的日誌下面只是堆棧跟蹤前:
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 [[email protected]3947]
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
下面是一些相關的代碼。首先,從我的彈簧配置XML摘錄:
<bean id="entityManagerFactory" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
<property name="dataSource" ref="dataSource" />
<property name="packagesToScan" value="com.taubler.oversite.entities" />
<property name="jpaVendorAdapter">
<bean class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter" />
</property>
<property name="jpaProperties">
<props>
<prop key="hibernate.hbm2ddl.auto">update</prop>
<prop key="hibernate.dialect">org.hibernate.dialect.MySQLInnoDBDialect</prop>
<prop key="hibernate.show_sql">true</prop>
<prop key="hibernate.jdbc.batch_size">20</prop>
<prop key="hibernate.ejb.naming_strategy">org.hibernate.cfg.ImprovedNamingStrategy</prop>
</props>
</property>
</bean>
<bean id="txManager" class="org.springframework.orm.jpa.JpaTransactionManager">
<property name="entityManagerFactory" ref="entityManagerFactory" />
</bean>
<tx:annotation-driven transaction-manager="txManager"/>
<bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<property name="driverClassName" value="${db.driver}" />
<property name="url" value="${db.url}" />
<property name="username" value="${db.username}" />
<property name="password" value="${db.password}" />
</bean>
示例業務邏輯(管理器)類。這個類是@Autowired
到控制器用SpringMVC,所以控制器被調用代理:
...
@Autowired
private EmailAddressDao emailAddressDao;
...
@Override
@Transactional
public EmailAddress addEmailAddress(User user, String email) {
EmailAddress emailAddress = new EmailAddress(user, email);
emailAddress.setMain(false);
emailAddress.setValidated(false);
emailAddressDao.insert(emailAddress);
this.initiateEmailValidation(emailAddress);
return emailAddress;
}
而由經理叫DAO:
...
@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
之間似乎有根本的不同。
就是這樣;謝謝。我沒有意識到我每次都會創建一個新的EntityManager,但現在這樣做非常合理。另外,關於HibernateTemplate工作的公平點並不是「正確」設置的證明。雖然,尤其是在傳播= REQUIRED的情況下,嵌套事務方法*應該非常好,並且只會導致一個事務。雖然我讀過Spring事務傳播與JPA事務管理器有不同的表現。 – 2014-09-24 06:41:09