2011-12-28 3 views
2

В моей Spring 2.5.6 + Hibernate app Мне нужно читать/записывать данные в/из нескольких баз данных с разными схемами. Приложение находится на Tomcat, поэтому я бы предпочел не использовать JTA, так что мне не нужно переходить на полномасштабный сервер приложений.Spring + Hibernate: вместе с транзакционными и не транзакционными источниками данных

Итак, я решил иметь только один транзакционный источник данных. Я могу жить с другими, не являющимися транзакционными.

Но почему-то я не могу заставить его работать. Не могли бы вы дать мне понять, что я могу делать неправильно?

Это мой applicationContext.xml:

<bean id="sessionFactory" class="org.springframework.orm.hibernate3.LocalSessionFactoryBean"> 
    <property name="dataSource" ref="dataSource"/> 
    <!-- ..configuration.. --> 
</bean> 

<bean id="nonTransactionalSessionFactory" class="org.springframework.orm.hibernate3.LocalSessionFactoryBean"> 
    <property name="dataSource" ref="nonTransactionalDataSource" /> 
    <!-- ..configuration.. --> 
</bean> 

<bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close"> 
    <!-- ..configuration.. --> 
</bean> 

<bean id="nonTransactionalDataSource" class="org.apache.commons.dbcp.BasicDataSource"> 
    <!-- ..configuration.. --> 
</bean> 

<bean id="txManager" class="org.springframework.orm.hibernate3.HibernateTransactionManager"> 
    <property name="sessionFactory" ref="sessionFactory"/> 
</bean> 

<bean id="daoHolder" class="com.app.services.TransactionTest$DaoHolder"/> 

<tx:annotation-driven transaction-manager="txManager"/> 

<bean id="transactionalDao" class="com.app.services.TransactionalDaoImpl"> 
    <property name="sessionFactory" ref="sessionFactory" /> 
</bean> 

<bean id="nonTransactionalDao" class="com.app.services.NonTransactionalDaoImpl"> 
     <property name="sessionFactory" ref="nonTransactionalSessionFactory" /> 
</bean> 

Как вы можете видеть выше, является лишь определение двух сессионных заводов, каждый из которых использует свой собственный источник данных. Менеджер транзакций использует только одну из этих сессионных фабрик и настраивается управление tx, основанное на аннотациях.

Вот мой блок тест, в котором я пытаюсь проверить поведение транзакционной:

@RunWith(SpringJUnit4ClassRunner.class) 
@ContextConfiguration(locations = {"/applicationContext.xml"}) 
public class TransactionTest { 

@Autowired 
private DaoHolder daoHolder; 

@Test 
public void testTransactions() throws Exception { 

    try { 
     daoHolder.runTransactionalMethod(); 
    } catch (Exception exception) { 
     System.out.println("Exception caught"); 
    } 
} 

public static class DaoHolder { 

    @Autowired 
    private TransactionalDao transactionalDao; 
    @Autowired 
    private NonTransactionalDao nonTransactionalDao; 

    @Transactional(readOnly = false, propagation = Propagation.REQUIRES_NEW, rollbackFor={Exception.class}) 
    private void runTransactionalMethod() throws Exception { 
     transactionalDao.insertRow(); 
     nonTransactionalDao.insertRow(); 
     throw new Exception(); 
    } 

} 

В результате проведенной проверки, я ожидал, что новая строка вставляется в не транзакционный источник данных, потому что изменения на транзакционном источнике данных должны быть отброшены, потому что есть исключение. Однако после прохождения этого теста я вижу строки, вставленные в оба источника данных.

EDIT: Я переехал немного дальше. Я превратил DaoHolder в интерфейс, переместил вышеуказанную логику в класс, реализующий интерфейс (DaoHolderImpl), и пометил также класс (а не только метод) с помощью @Transactional. Я также добавил этот класс как Spring Bean. Итак, теперь Spring обрабатывает мои транзакции. Но на этот раз, бросая Exception, новая строка откатывается из обоих источников данных, а не только транзакционной. Это все еще не то, что я ожидал:/

Кто-нибудь видит, что я делаю неправильно? Спасибо заранее,

Питер

ответ

1

насчет сдачи контрольных точек на линии «бросить исключение», так что вы можете увидеть, если один или оба баз данных имеют эту линию?

Он не исправляет вашу странную проблему отката, а не говорит о том, работает ли ваш источник данных без транзакций.

Вы бы скорее включить рессора/спящий режим протоколирования, чтобы посмотреть, что происходит о сделках ...

+0

Нет проблем, спасибо за попробовать, хотя :) Я только что получил его в точку, где после того, как бросать исключения Я получаю откат (пришлось добавить @Transactional ко всему классу DaoHolder), но на этот раз изменения от обоих DAO, похоже, были отброшены, потому что ничего не было вставлено. Это удивительно для меня, потому что я ожидал, что только транзакционное дао вернется. В любом случае - это по-прежнему не то поведение, в котором я нуждаюсь. – machinery

+0

Возможно, вам необходимо настроить флешмод вашей не транзакционной базы данных. Возможно, что строка вставлена ​​в ваш не транзакционный сеанс, но флеш просто не произошел. Вы видите что-нибудь в журналах спящего SQL (свойство show_sql)? Как насчет вашей конфигурации db? Вы установили что-то вроде autocommit = true или что-то в этом роде? –

+0

Ну, если я не бросаю исключение, я вижу обе вставки в журналах спящего SQL. Если я выброшу Exception, я не вижу никаких вставок. Хмм .. в журналах я вижу это: ** Открыл новый сеанс [[email protected]] для транзакции Hibernate ** только один раз. Поэтому я полагаю, что моя проблема вызвана тем, что в действительности обе эти операции выполняются на одном сеансе Hibernate. Почему это так и как я могу его изменить? – machinery

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