一个事务中的Hibernate和JDBC

时间:2010-11-11 10:00:39

标签: java hibernate spring jdbc transactions

我有一个标记为@Transactional的方法。 它由几个函数组成,其中一个使用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 {
               ... 
            }
        });

用于hibernate函数。 感谢。

3 个答案:

答案 0 :(得分:11)

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

然后,如果您真的需要它,请使用Session.doWork(..)。如果你的hibernate版本还没有这个方法,请从Connection获取session.connection()

答案 1 :(得分:2)

如果使用正确的Spring设置,则可以在同一事务中使用JDBC和Hibernate:

<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)获取连接
  • 使用TransactionAwareDataSourceProxy将您传递给DAO的数据源(但不一定是传递给SessionFactory的数据源)包裹起来

后者是首选,因为它隐藏了代理数据源中的DataSourceUtils.getConnection。

这当然是XML路径,应该很容易将其转换为基于注释。

答案 2 :(得分:2)

问题是,在立即执行SQL时,Hibernate引擎上的操作不会导致。你可以在Hibernate会话上手动调用flush来触发它。然后,在同一事务中的SQL代码中可以看到hibernate中所做的更改。只要你DataSourceUtils.getConnection获得SQL连接,因为只有这样你才能让它们在同一个交易中运行 ......

在相反的方向上,这更棘手,因为你有1级缓存(会话缓存),也可能是2级缓存。对于二级缓存,如果缓存行,则对Hibernate所做的所有更改都将对Hibernate不可见,直到缓存过期。