简体   繁体   English

一个事务中的Hibernate和JDBC

[英]Hibernate and JDBC in one transaction

I have a method, marked as @Transactional. 我有一个方法,标记为@Transactional。 It consists of several functions, one of them uses JDBC and the second one - Hibernate, third - JDBC. 它由几个函数组成,其中一个使用JDBC,第二个是Hibernate,第三个是JDBC。 The problem is that changes, made by Hibernate function are not visible in the last functions, that works with JDBC. 问题是Hibernate函数所做的更改在最后一个与JDBC一起使用的函数中是不可见的。

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

All functions are configured to use the same datasource: 所有函数都配置为使用相同的数据源:

<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 is used in the code. myDataSource bean用于代码中。 myDataSource.getConnection() is used to work with connections in jdbc functions and myDataSource.getConnection()用于处理jdbc函数和中的连接

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

is used in hibernate function. 用于休眠函数。 Thanks. 谢谢。

First, avoid using JDBC when using hibernate. 首先,避免在使用hibernate时使用JDBC。

Then, if you really need it, use to Session.doWork(..) . 然后,如果您真的需要它,请使用Session.doWork(..) If your hibernate version does not yet have this method, obtain the Connection from session.connection() . 如果你的hibernate版本还没有这个方法,请从session.connection()获取Connection

The problem is, the operations on Hibernate engine does not result in immediate SQL execution. 问题是,Hibernate引擎的操作不会导致立即执行SQL。 You can trigger it manually calling flush on Hibernate session. 你可以在Hibernate会话上手动调用flush来触发它。 Then the changes made in hibernate will be visible to the SQL code within the same transaction. 然后,在同一事务中的SQL代码中可以看到hibernate中所做的更改。 As long as you do DataSourceUtils.getConnection to get SQL connection, because only then you'll have them run in the same transaction ... 只要你做DataSourceUtils.getConnection来获得SQL连接,因为只有这样你才能让他们在同一个事务中运行...

In the opposite direction, this is more tricky, because you have 1nd level cache (session cache), and possibly also 2nd level cache. 在相反的方向上,这更棘手,因为你有一级缓存(会话缓存),也可能是二级缓存。 With 2nd level cache all changes made to database will be invisible to the Hibernate, if the row is cached, until the cache expires. 对于二级缓存,如果缓存行,则对Hibernate所做的所有更改都将对Hibernate不可见,直到缓存过期。

You can use JDBC and Hibernate in the same transaction if you use the right Spring setup: 如果使用正确的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>

This assumes that the JDBC portion of your DAO uses JdbcTemplate. 这假设您的DAO的JDBC部分使用JdbcTemplate。 If it doesn't you have a few options: 如果没有,你有几个选择:

  • Use DataSourceUtils.getConnection(javax.sql.DataSource) to get a connection 使用DataSourceUtils.getConnection(javax.sql.DataSource)获取连接
  • Wrap the DataSource you pass to your DAO (but not necessarily the one you pass to the SessionFactory) with a TransactionAwareDataSourceProxy 使用TransactionAwareDataSourceProxy将传递给您的DAO的数据源(但不一定是传递给SessionFactory的数据源)包装起来

The latter is preferred since it hidse the DataSourceUtils.getConnection inside the proxy datasource. 后者是首选,因为它隐藏了代理数据源中的DataSourceUtils.getConnection。

This is of course the XML path, it should be easy to convert this to annotation based. 这当然是XML路径,应该很容易将其转换为基于注释。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM