@EnableTransactionManagement аннотация с 2 менеджерами транзакций - PullRequest
24 голосов
/ 08 ноября 2011

Я использую аннотацию @Configuration для конфигурации Spring вместо XML-файла. Я настраиваю 2 источника данных с разными фабриками сеансов и разными менеджерами транзакций. Я застрял с проблемой здесь для @EnableTransactionManagement аннотации. Я прочитал в своей документации, что,

@EnableTransactionManagement более гибкий; это отступит к поиск по типу для любого компонента PlatformTransactionManager в контейнер. Таким образом, имя может быть «txManager», «TransactionsManager» или «тм»: это просто не имеет значения.

Это означает, что любое имя, которое я даю методу, всегда будет искать метод, который возвращает объект PlatformTransactionManager, пока у меня есть 2 менеджера транзакций. Теперь проблема в том, что когда я тестирую этот класс, он выдает ошибку:

org.springframework.beans.factory.NoSuchBeanDefinitionException: Не определен уникальный компонент типа [org.springframework.transaction.PlatformTransactionManager]: ожидается один компонент, но найден 2

Я даже пытался иметь 2 разных класса конфигурации, но тщетно. В конфигурации xml это было не так. Я зарегистрировал оба менеджера транзакций с двумя тегами <tx:annotation-driven transaction-manager="" />, и он работал нормально. Но не в состоянии сделать то же самое здесь с аннотациями.

Что мне делать, если я хочу настроить 2 источника данных с 2 различными менеджерами транзакций в классе конфигурации с аннотацией Spring?

Ответы [ 6 ]

34 голосов
/ 27 декабря 2013

В вашем классе конфигурации используйте аннотацию @EnableTransactionManagement.

Определите менеджер транзакций в этом классе как:

    @Bean(name="txName")
    public HibernateTransactionManager txName() throws IOException{
        HibernateTransactionManager txName= new HibernateTransactionManager();
        txName.setSessionFactory(...);
        txName.setDataSource(...);
        return txName;
   }

Там, в вашем классе / методе, который выполняет транзакционное задание (я), аннотируйте следующим образом:

@Transactional("txName")

или

@Transactional(value = "txName")

Так вы бы связали квалифицированного менеджера транзакций с именем, где бы он вам ни понадобился. Теперь вы можете иметь столько менеджеров транзакций, сколько захотите, и использовать их соответственно, где вам нужно.

8 голосов
/ 17 сентября 2014

На случай, если кто-нибудь столкнется с этой проблемой, я нашел решение:

@Configuration
@EnableTransactionManagement
@DependsOn("myTxManager")
@ImportResource("classpath:applicationContext.xml")
public class AppConfig implements TransactionManagementConfigurer {

@Autowired
private PlatformTransactionManager myTxManager;

...

@Override
public PlatformTransactionManager annotationDrivenTransactionManager() {
    return this.myTxManager;
}

Таким образом, вы можете использовать определенный txManager, определенный в конфигурации xml.

Если вы хотите определить txManager , используемый на уровне обслуживания, вы должны удалить аннотацию @EnableTransactionManagement из класса @Configuration и указать txManager в аннотациях @Transactional, например

@Service
@Transactional(value="myTxManager", readOnly = true)
public class MyServiceImpl implements MyService { ... }
5 голосов
/ 08 ноября 2011

Из java doc

Для тех, кто хочет установить более прямую связь между
@EnableTransactionManagement и точным компонентом менеджера транзакций, который будет использоваться,TransactionManagementConfigurer Интерфейс обратного вызова может быть реализован - обратите внимание на пункт Implements и @Override -аннотированный метод ниже:

Ваш класс @Configuration должен реализовать интерфейс TransactionManagementConfigurer - реализовать annotationDrivenTransactionManagerкоторый возвратит ссылку на transactionManager, который следует использовать.

1 голос
/ 07 декабря 2011

Я не уверен, почему вы используете два TransactionManager.Вы можете рассмотреть возможность использования одного и того же TransactionManager для нескольких источников данных через AbstractRoutingDataSource.Пожалуйста, обратитесь

http://blog.springsource.org/2007/01/23/dynamic-datasource-routing/

за образец по его использованию.

0 голосов
/ 16 августа 2018

Попробуйте использовать цепочечный TransactionalManager

import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.transaction.ChainedTransactionManager;
import org.springframework.transaction.PlatformTransactionManager;

@Configuration
public class ChainedDBConfig {

    @Bean("chainedTransactionManager")
    public PlatformTransactionManager transactionManager(
            @Qualifier("database1TransactionManager") final PlatformTransactionManager db1PlatformTransactionManager,
            @Qualifier("database2TransactionManager") final PlatformTransactionManager db2PlatformTransactionManager) {

        return new ChainedTransactionManager(db1PlatformTransactionManager, db2PlatformTransactionManager);
    }

}

И поместите следующую аннотацию на ваш класс обслуживания:

@Transactional(transactionManager = "chainedTransactionManager")
public class AggregateMessagesJobIntegrationTest {
   ...
}

Вы также можете использовать его в интеграционных тестах:

@RunWith(SpringRunner.class)
@Transactional(transactionManager = "chainedRawAndAggregatedTransactionManager")
@Rollback
public class ExampleIntegrationTest extends AbstractIntegrationTest {
    ....
}

и будет выполнен откат для обоих менеджеров транзакций БД.

0 голосов
/ 26 сентября 2013

Некоторые другие ответы подразумевают, что использование двух менеджеров транзакций в некотором роде неправильно;тем не менее, XML-конфигурация Spring позволяет использовать несколько менеджеров транзакций, как указано в онлайн-документации (ниже).К сожалению, похоже, нет способа заставить аннотацию @EnableTransactionManagement работать аналогичным образом.В результате я просто использую аннотацию @ImportResource для загрузки XML-файла, который содержит строку <tx:annotation-driven/>.Это позволяет вам получить конфигурацию Java для большинства вещей, но все еще использовать @Transactional с необязательным квалификатором Transaction Manager.

http://docs.spring.io/spring/docs/3.1.x/spring-framework-reference/html/transaction.html

Большинству приложений Spring требуется толькоодин менеджер транзакций, но могут быть ситуации, когда вам нужно несколько независимых менеджеров транзакций в одном приложении.Атрибут value аннотации @Transactional может использоваться для необязательного указания идентификатора PlatformTransactionManager, который будет использоваться.Это может быть либо имя компонента, либо значение квалификатора компонента управления транзакциями.Например, используя обозначение квалификатора, следующий код Java

...