Hibernate и JDBC в одной транзакции - PullRequest
9 голосов
/ 11 ноября 2010

У меня есть метод, помеченный как @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>

В коде используется bean-компонент myDataSource. myDataSource.getConnection () используется для работы с соединениями в функциях jdbc и

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

используется в режиме гибернации. Благодаря.

Ответы [ 3 ]

11 голосов
/ 11 ноября 2010

Во-первых, избегайте использования JDBC при использовании hibernate.

Затем, если вам это действительно нужно, используйте Session.doWork(..).Если в вашей спящей версии этого метода еще нет, получите Connection из session.connection().

2 голосов
/ 19 июня 2012

Проблема в том, что операции над механизмом Hibernate не приводят к немедленному выполнению SQL.Вы можете запустить его вручную, вызвав flush в сеансе Hibernate.Тогда изменения, внесенные в hibernate, будут видны для кода SQL в рамках той же транзакции.Пока вы делаете DataSourceUtils.getConnection для получения SQL-соединения, потому что только тогда они будут выполняться в той же транзакции ...

В обратном направлении, это более сложнопотому что у вас есть кэш 1-го уровня (кеш сеанса) и, возможно, также кэш 2-го уровня.При использовании кеша 2-го уровня все изменения, внесенные в базу данных, будут невидимы для Hibernate, если строка будет кэширована, до истечения срока действия кеша.

2 голосов
/ 27 октября 2011

Вы можете использовать JDBC и Hibernate в одной транзакции, если используете правильную настройку Spring:

<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>

Предполагается, что часть JDBC вашего DAO использует JdbcTemplate. Если это не так, у вас есть несколько вариантов:

  • Используйте DataSourceUtils.getConnection (javax.sql.DataSource), чтобы получить соединение
  • Оберните источник данных, который вы передаете в DAO (но не обязательно тот, который вы передаете в SessionFactory) с TransactionAwareDataSourceProxy

Последний вариант предпочтителен, поскольку он скрывает DataSourceUtils.getConnection внутри источника данных прокси.

Это, конечно, путь XML, его легко преобразовать в аннотации.

...