В моей 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, новая строка откатывается из обоих источников данных, а не только транзакционной. Это все еще не то, что я ожидал:/
Кто-нибудь видит, что я делаю неправильно? Спасибо заранее,
Питер
Нет проблем, спасибо за попробовать, хотя :) Я только что получил его в точку, где после того, как бросать исключения Я получаю откат (пришлось добавить @Transactional ко всему классу DaoHolder), но на этот раз изменения от обоих DAO, похоже, были отброшены, потому что ничего не было вставлено. Это удивительно для меня, потому что я ожидал, что только транзакционное дао вернется. В любом случае - это по-прежнему не то поведение, в котором я нуждаюсь. – machinery
Возможно, вам необходимо настроить флешмод вашей не транзакционной базы данных. Возможно, что строка вставлена в ваш не транзакционный сеанс, но флеш просто не произошел. Вы видите что-нибудь в журналах спящего SQL (свойство show_sql)? Как насчет вашей конфигурации db? Вы установили что-то вроде autocommit = true или что-то в этом роде? –
Ну, если я не бросаю исключение, я вижу обе вставки в журналах спящего SQL. Если я выброшу Exception, я не вижу никаких вставок. Хмм .. в журналах я вижу это: ** Открыл новый сеанс [[email protected]] для транзакции Hibernate ** только один раз. Поэтому я полагаю, что моя проблема вызвана тем, что в действительности обе эти операции выполняются на одном сеансе Hibernate. Почему это так и как я могу его изменить? – machinery