2010-11-11 2 views
9

У меня есть метод, обозначенный как @Transactional. Он состоит из нескольких функций, один из которых использует 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 фасоль используется в коде. myDataSource.getConnection() используется для работы с соединениями в функциях и JDBC

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

используется в функции спящего режима. Спасибо.

ответ

10

Во-первых, во избежание использования JDBC при использовании спящего режима.

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

+2

Для тех, кто получит от Google, мое решение этой проблемы. Я добавил session.flush() в конце функции спящего режима. После этого результат записи доступен в следующей функции чтения jdbc (в той же транзакции). – alex543

2

Вы можете использовать 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), чтобы получить соединение
  • Оберните DataSource, который вы передаете ваш DAO (но не обязательно тот, который вы перейдите к SessionFactory) с TransactionAwareDataSourceProxy

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

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

2

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

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

Смежные вопросы