Как настроить управление транзакциями для работы с двумя разными db в Spring?

У меня 2 базы данных (MySql и HSQLDB). Я настроил 2 источника данных и 2 компонента EntityManagerFactory. Я также могу настроить 2 соответствующих bean-компонента JpaTransactionManager.

Но я не знаю, как указать, какие из них следует использовать для управления транзакциями для конкретного класса обслуживания. Я хочу использовать для этой цели аннотацию @Transactional, но на самом деле я могу указать только один из txManager:

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

Какой выход из этой ситуации?


person Roman    schedule 25.12.2009    source источник
comment
stackoverflow.com/questions/1961371/   -  person Bozho    schedule 25.12.2009


Ответы (4)


javadoc для JpaTransactionManager есть несколько советов по этому поводу:

Этот диспетчер транзакций подходит для приложений, которые используют одну JPA EntityManagerFactory для доступа к транзакционным данным. JTA (обычно через JtaTransactionManager) необходим для доступа к нескольким транзакционным ресурсам в рамках одной транзакции. Обратите внимание, что вам необходимо соответствующим образом настроить своего провайдера JPA, чтобы он участвовал в транзакциях JTA.

Другими словами, если вы обнаружите, что у вас несколько менеджеров объектов с соответствующими менеджерами tx, вам следует подумать об использовании одного _ 1_. Менеджеры сущностей должны иметь возможность участвовать в транзакциях JTA, и это даст вам полную транзакционную возможность для обоих менеджеров сущностей, не беспокоясь о том, в каком диспетчере сущностей вы находитесь в любой момент.

Конечно, JtaTransactionManager действительно требуется сервер приложений с полной поддержкой JTA, а не ванильный механизм сервлетов, такой как Tomcat.

person skaffman    schedule 25.12.2009
comment
Я, наверное, чего-то не понимаю, но я думал, что диспетчер транзакций, используемый в Spring, основан на диспетчере транзакций базы данных, т.е. мы должны создать столько tx-менеджеров, сколько разных баз данных мы используем. Это неправильно? - person Roman; 25.12.2009
comment
Все не так просто. Менеджеры Spring TX - это просто оболочки для других существующих механизмов, таких как транзакции JTA, JPA / Hibernate или JDBC. JTA не привязан к одной базе данных, это распределенный tx-менеджер с несколькими базами данных. Использование Spring на самом деле не меняет того, как следует использовать лежащие в основе механизмы, оно просто упрощает его. - person skaffman; 26.12.2009
comment
Спасибо, для меня это звучит несколько неожиданно, поищу в документации Sun. - person Roman; 26.12.2009
comment
Что произойдет, если я аннотирую метод двумя @Transactional (), например: @Transactional (transactionManager = customerTransactionManager), @Transactional (transactionManager = orderTransactionManager)? Я хотел бы знать, как обрабатывать обе транзакции БД одним методом. - person Radu Toader; 06.09.2016

Объявите свой <tx:annotation-driven> без атрибута transaction-manager, объявите квалификаторы для менеджеров транзакций следующим образом:

<bean id="jpaTransactionManager" class="org.springframework.orm.jpa.JpaTransactionManager">
    <property name="entityManagerFactory" ref="entityManagerFactory" />
    <qualifier value="txManager1"/>
</bean>

Используйте этот квалификатор в @Transactional как значение для выбора одного из менеджеров транзакций:

@Transactional("txManager1")

или с другими свойствами:

@Transactional(value = "txManager1", readOnly = true)   
person axtavt    schedule 25.12.2009
comment
Это решение работает. Однако, если у вас есть квалификатор в аннотации @Transactional, вы должны указать диспетчер транзакций с настроенным элементом квалификатора. Поначалу я думал, что все возьмет на себя диспетчер транзакций по умолчанию, но для меня это было не так. Он пожаловался, что у меня не настроен надлежащий квалификатор для моего bean-компонента диспетчера транзакций. - person Jorge; 13.05.2011
comment
Обратите внимание, что это относится к Spring 3 и позже. - person java25; 02.07.2014

Поскольку это после долгого времени с правильных ответов.

Скаффман может быть прав с точки зрения удобства использования JpaTransactionManager для нескольких баз данных.

Но есть рабочее решение для использования двух разных баз данных с двумя разными JpaTransactionManager.

  @Bean(name = "db2TransactionManager")
  public PlatformTransactionManager transactionManager2() throws NamingException {
    JpaTransactionManager txManager = new JpaTransactionManager(entityManagerFactory());
    return txManager;
  }

  @Bean
  @Primary
  public PlatformTransactionManager transactionManager() throws Exception {
     JpaTransactionManager txManager = new JpaTransactionManager(entityManagerFactory());
    txManager.setNestedTransactionAllowed(true);
    return txManager;
  }

@Primary следует использовать для указания тех, где вы не указываете имя квалификатора в @Transactional

person raksja    schedule 21.09.2013

Для этого вам необходимо указать два менеджера транзакций в application-context.xml, как показано ниже:

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

Атрибут @Transactional теперь будет использовать соответствующий диспетчер транзакций.

person Mital Pritmani    schedule 21.10.2011
comment
Это сработало для меня, и мне не нужно было указывать квалификатор в bean-компонентах txManager или в аннотации @Transactional. Я также смог получить доступ к двум различным фабрикам сеансов. - person jonnysamps; 11.11.2011
comment
Я, то же самое и со мной. Мне также не нужно было указывать квалификатор с аннотацией @Transactional. - person Mital Pritmani; 11.11.2011
comment
Интересно, если я посмотрю на AnnotationDrivenBeanDefinitionParser, который обрабатывает tx:annotation-driven, все выполняется только один раз для каждого контекста! Так что вторая строка совершенно бесполезна. - person Arne Burmeister; 22.11.2011
comment
Это сработало для меня! Жаль, что в официальном документе Spring не упоминается этот трюк для настройки нескольких DataSourceTransactionManager. - person tonga; 24.12.2013