2014-09-24 46 views
1

我有一個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) 
    ... 

請記住,我的代碼工作正常使用HibernateTemplateSessionFactoryHibernateTransactionManager,等我的業務邏輯類,以及我的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方法...沒有任何作用。

有什麼想法? HibernateTransactionManagerJpaTransactionManager之間似乎有根本的不同。

回答

4
@PersistenceUnit 
private EntityManagerFactory entityManagerFactory; 

protected final EntityManager getEntityManager() { 
    return entityManagerFactory.createEntityManager(); 
} 

問題是你自己創建一個實體管理器,不。只需注入EntityManager而不是EntityManagerFactory,並註明@PersistenceContext而不是@PersistenceUnit。 Spring會考慮使其成爲當前事務的約束。

@PersistenceContext 
private EntityManager entityManager; 

protected final EntityManager getEntityManager() { 
    return entityManger; 
} 

如果你真的想保持注射EntityManagerFactory使用EntityManagerFactoryUtilsgetTransactionalEntityManager方法獲取Spring管理EntityManager實例。

protected final EntityManager getEntityManager() { 
    return EntityManagerFactoryUtils.getTransactionalEntityManager(entityManagerFactory); 
} 

此外,它與「簡單」休眠的事實並不意味着你的設置必須是正確的。你提到你使用了HibernateTemplate,它基本上可以在沒有正確的事務處理設置的情況下工作,因爲它只是爲了手頭的行動而開始新的轉換。所以它很可能是應用程序似乎正確地工作,而實際上它沒有。也許你有多個事務,你希望有一個(來自服務層)。

另外一個需要注意的是,你的代碼可能是危險的

public boolean insert(Entity o) { 
    o.setCreated(new Date()); 
    this.getEntityManager().persist(o); 
    this.getEntityManager().flush(); 
    return true; 
} 

這,你的情況,可能會導致創建2個不同的EntityManager這麼你可能已經刷新一個又一個,你在堅持。下一步您不應該調用flush,因爲交易結束時會執行此操作。

+0

就是這樣;謝謝。我沒有意識到我每次都會創建一個新的EntityManager,但現在這樣做非常合理。另外,關於HibernateTemplate工作的公平點並不是「正確」設置的證明。雖然,尤其是在傳播= REQUIRED的情況下,嵌套事務方法*應該非常好,並且只會導致一個事務。雖然我讀過Spring事務傳播與JPA事務管理器有不同的表現。 – 2014-09-24 06:41:09

2

你需要注入EntityManager直接與@PersistenceContext註釋,而不是PersistenceUnit

相關問題