Ответ 1
Вопрос:
Я только что провел последний день с этим точным вопросом: Почему транзакции между источниками данных работают с одним менеджером транзакций в спящем режиме?
Как и вы, я также читал в нескольких местах, что мне нужно было использовать JtaTransactionManager... и получается, что они были правы! Я объясню:
Конфигурация:
Как и вы, я начал с 2 источников данных, 2 сессионных фабрик и 1 HibernateTransactionManager.
Мой тестовый код также очень похож на ваш, и я мог успешно сохранять объекты в обеих базах данных. Если я вручную выброшу исключение, в базе данных не появится ни одно сохранение. Таким образом, казалось, что оба они вернулись правильно. Однако, когда я включил ведение журнала отладки в спящем режиме, я увидел, что ни одна из них не была отправлена в базы данных, поэтому откат не был.
Проблема заключается в тестировании, поэтому я изменю ваш тест, чтобы доказать, что один менеджер транзакций фактически не работает!
Необходимое изменение было предложено JB Nizet 2 января:
Вы пытались вызывать флеш на обеих сессиях, прежде чем выбрасывать исключение?
Лучший тест:
Сначала добавьте функцию флеша к каждому из ваших DAO. Это выглядит так:
public void flush() {
sessionFactory.getCurrentSession().flush();
}
Вероятно, ваш вид будет выглядеть следующим образом:
public void flush() {
getHibernateTemplate().flush();
}
Теперь измените свой тест, чтобы очистить каждое dao до исключения:
@Transactional("txManager")
public class DaoHolder {
@Transactional(value="txManager", readOnly=false, propagation=Propagation.REQUIRES_NEW, rollbackFor={Exception.class})
private void runTransactionalMethod() throws Exception {
dao1.insertRow();
dao2.insertRow();
dao1.flush();
dao2.flush();
throw new Exception();
}
//...
}
Результат:
Откатился только источник данных, связанный с txManager. Это имеет смысл, потому что txManager не знает о другом источнике данных.
Резюме:
В моем случае мне не нужно обращаться к 2 базам данных в одной транзакции, отдельные транзакции прекрасны. Поэтому я просто определил второго менеджера транзакций:
<bean id="txManager2" class="org.springframework.orm.hibernate3.HibernateTransactionManager">
<property name="sessionFactory" ref="sessionFactory2"/>
</bean>
И ссылается на это по имени в аннотации Transactional, где я обращаюсь ко второй базе данных:
@Transactional(value="txManager2"...)
Теперь я могу получить аннотированные транзакции для моей второй базы данных, но я до сих пор не могу получить транзакции в обеих базах данных... для этого вам понадобится JtaTransactionManager.