2010-11-11 68 views
9

我有一個方法,標記爲@Transactional。 它由幾個函數組成,其中一個使用JDBC,第二個使用JDBC - Hibernate,第三個使用JDBC。 問題在於,由Hibernate函數所做的更改在最後一個可用於JDBC的函數中不可見。Hibernate和JDBC在一個事務中

@Transactional 
void update() { 
    jdbcUpdate1(); 
    hibernateupdate1(); 
    jdbcUpdate2(); // results of hibernateupdate1() are not visible here  
} 

所有功能都被配置成使用相同的數據源:

<bean id="myDataSource" class="org.springframework.jdbc.datasource.TransactionAwareDataSourceProxy"> 
     <property name="targetDataSource" ref="targetDataSource"/> 
    </bean> 

    <bean id="targetDataSource" class="org.apache.commons.dbcp.BasicDataSource" 
      destroy-method="close" lazy-init="true" scope="singleton"> 
     <!-- settings here --> 
    </bean> 

myDataSource bean是在代碼中使用。 myDataSource.getConnection()用於在jdbc函數中使用連接,並且

getHibernateTemplate().execute(new HibernateCallback() { 
      public Object doInHibernate(Session session) throws HibernateException, SQLException { 
       ... 
      } 
     }); 

用於休眠功能。 謝謝。

回答

10

首先,避免在使用hibernate時使用JDBC。

然後,如果您確實需要它,請使用Session.doWork(..)。如果您的休眠版本還沒有此方法,請從session.connection()獲取Connection

+2

對於那些來自Google的人來說,我的解決方案就是針對這個問題。我在hibernate flush函數的最後添加了session.flush()。之後,它的寫入結果在下一個jdbc讀取函數中可用(在同一個事務中)。 – alex543 2010-11-11 13:53:20

2

您可以使用JDBC,並在同一個事務休眠,如果你使用正確的春天設置:

<bean id="sessionFactory" class="org.springframework.orm.hibernate3.LocalSessionFactoryBean"> 
    <property name="dataSource" ref="dataSource"/> 
</bean> 

<bean id="transactionManager" class="org.springframework.orm.hibernate3.HibernateTransactionManager"> 
    <property name="sessionFactory" ref="sessionFactory"/> 
</bean> 

<bean id="myDao" class="org.springframework.transaction.interceptor.TransactionProxyFactoryBean"> 
    <property name="transactionManager" ref="transactionManager"/> 
    <property name="target"> 
     <bean class="MyDaoImpl"> 
      <property name="dataSource" ref="dataSource"/> 
      <property name="sessionFactory" ref="sessionFactory"/> 
     </bean> 
    </property> 
    <property name="transactionAttributes"> 
     <props> 
      <prop key="get*">PROPAGATION_SUPPORTS,readOnly</prop> 
      <prop key="*">PROPAGATION_REQUIRED</prop> 
     </props> 
    </property> 
</bean> 

這是假設你的DAO的JDBC部分使用的JdbcTemplate。如果沒有,你有幾個選擇:

  • 使用DataSourceUtils.getConnection(javax.sql.DataSource中)來獲取連接
  • 包裹傳遞給你的DAO(但不一定是一個你的數據源傳遞給SessionFactory)使用TransactionAwareDataSourceProxy

後者是首選,因爲它隱藏了代理數據源中的DataSourceUtils.getConnection。

這當然是XML路徑,應該很容易將其轉換爲基於註釋。

2

問題是,Hibernate引擎上的操作在執行即時SQL時不會導致。您可以在Hibernate會話中手動調用flush來觸發它。然後,在同一個事務中,對hibernate所做的更改將對SQL代碼可見。只要你做DataSourceUtils.getConnection獲得SQL連接,因爲只有這樣你就會有他們在同一個事務運行...

在相反的方向,這是比較棘手的,因爲你有1ND級緩存(會話緩存),也可能還有二級緩存。對於第二級緩存,如果該行被緩存,直到緩存過期,所有對數據庫所做的更改將對Hibernate不可見。