alex543
alex543

Reputation: 251

Hibernate and JDBC in one transaction

I have a method, marked as @Transactional. It consists of several functions, one of them uses JDBC and the second one - Hibernate, third - JDBC. The problem is that changes, made by Hibernate function are not visible in the last functions, that works with 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.getConnection() is used to work with connections in jdbc functions and

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

is used in hibernate function. Thanks.

Upvotes: 10

Views: 7838

Answers (3)

Cjxcz Odjcayrwl
Cjxcz Odjcayrwl

Reputation: 22847

The problem is, the operations on Hibernate engine does not result in immediate SQL execution. You can trigger it manually calling flush on Hibernate session. Then the changes made in hibernate will be visible to the SQL code within the same transaction. As long as you do DataSourceUtils.getConnection to get SQL connection, because only then you'll have them run in the same transaction...

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.

Upvotes: 2

Bill Poitras
Bill Poitras

Reputation: 667

You can use JDBC and Hibernate in the same transaction if you use the right Spring setup:

<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. If it doesn't you have a few options:

  • Use DataSourceUtils.getConnection(javax.sql.DataSource) to get a connection
  • Wrap the DataSource you pass to your DAO (but not necessarily the one you pass to the SessionFactory) with a TransactionAwareDataSourceProxy

The latter is preferred since it hidse the DataSourceUtils.getConnection inside the proxy datasource.

This is of course the XML path, it should be easy to convert this to annotation based.

Upvotes: 2

Bozho
Bozho

Reputation: 597046

First, avoid using JDBC when using hibernate.

Then, if you really need it, use to Session.doWork(..). If your hibernate version does not yet have this method, obtain the Connection from session.connection().

Upvotes: 12

Related Questions