2010-11-11 55 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不可见。