В моем приложении Spring 2.5.6 + Hibernate мне нужно читать / записывать данные в / из нескольких баз данных с разными схемами. Приложение находится на Tomcat, поэтому на данный момент я бы предпочел не использовать JTA, чтобы мне не приходилось переходить на полноценный сервер приложений.
Поэтому я решил использовать только один источник транзакционных данных. Я могу жить с другими, не ведя транзакций.
Но как-то не могу заставить его работать. Не могли бы вы дать мне понять, что я делаю не так?
Это мой 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();
}
}
В результате вышеупомянутого теста я ожидаю, что новая строка будет вставлена в нетранзакционный источник данных, потому что изменения в транзакционном источнике данных должны быть отменены, потому что возникает исключение. Однако после прохождения этого теста я вижу строки, вставленные в оба источника данных.
РЕДАКТИРОВАТЬ: Я двинулся немного дальше. Я превратил DaoHolder в интерфейс, переместил вышеуказанную логику в класс, реализующий интерфейс (DaoHolderImpl), и пометил также класс (а не только метод) с помощью @Transactional. Я также добавил этот класс как Spring Bean. Итак, теперь Spring обрабатывает мои транзакции. Но на этот раз при выдаче исключения новая строка откатывается из обоих источников данных, а не только из транзакционного. Это все еще не то, чего я ожидал: /
Кто-нибудь видит, что я делаю не так? Заранее спасибо,
Питер