我使用@Configuration
注释来配置spring而不是xml文件。我正在配置具有不同会话工厂和不同事务管理器的2个数据源。我在这里遇到@EnableTransactionManagement
注释的问题。我在其文档中读到了
@EnableTransactionManagement
更灵活;它将回归到 对类中任何PlatformTransactionManager
bean的类型查找 容器。因此,名称可以是" txManager"," transactionManager",或 " tm":它无所谓。
这意味着我给方法提供的任何名称,它总是会搜索返回PlatformTransactionManager
对象的方法,而我有2个事务管理器。现在问题是,当我测试这个类时,它给了我错误:
org.springframework.beans.factory.NoSuchBeanDefinitionException
:没有定义[org.springframework.transaction.PlatformTransactionManager
]类型的唯一bean:预期的单个bean但找到了2
我甚至试图拥有2个不同的配置类但是徒劳无功。在xml配置中,情况并非如此。我用两个<tx:annotation-driven transaction-manager="" />
标签注册了我的两个交易管理器,它运行正常。但是这里不能用注释做同样的事。
如果我想在Spring注释配置类中配置2个具有2个不同事务管理器的数据源,我该怎么办?
答案 0 :(得分:33)
在配置类中,使用@EnableTransactionManagement
注释。
将此类中的事务管理器定义为:
@Bean(name="txName")
public HibernateTransactionManager txName() throws IOException{
HibernateTransactionManager txName= new HibernateTransactionManager();
txName.setSessionFactory(...);
txName.setDataSource(...);
return txName;
}
在您的类/方法中执行事务性作业,注释如下:
@Transactional("txName")
或
@Transactional(value = "txName")
这就是如何将名称限定的事务管理器绑定到您需要的位置。您现在可以拥有任意数量的事务管理器,并根据需要随时使用它。
答案 1 :(得分:8)
万一有人遇到这个问题,我找到了一个解决方案:
@Configuration
@EnableTransactionManagement
@DependsOn("myTxManager")
@ImportResource("classpath:applicationContext.xml")
public class AppConfig implements TransactionManagementConfigurer {
@Autowired
private PlatformTransactionManager myTxManager;
...
@Override
public PlatformTransactionManager annotationDrivenTransactionManager() {
return this.myTxManager;
}
通过这种方式,您可以使用xml配置中定义的特定txManager。
如果您想要定义服务级别使用的 txManager ,您应从<{1}}类删除 @EnableTransactionManagement
注释在@Configuration
注释中指定 txManager ,例如
@Transactional
答案 2 :(得分:5)
来自java doc
对于那些希望建立更直接关系的人
@EnableTransactionManagement
和要使用的确切事务管理器bean, 可以实现TransactionManagementConfigurer
回调接口 - 注意 implements子句和下面的@Override
- 注释方法:
您的@Configuration
课程需要实施TransactionManagementConfigurer
界面 - 实施annotationDrivenTransactionManager
,这将返回应该使用的transactionManager
的引用。
答案 3 :(得分:1)
我不确定您使用两个TransactionManagers的原因。您可以考虑通过AbstractRoutingDataSource将相同的TransactionManager用于多个数据源。请参考
http://blog.springsource.org/2007/01/23/dynamic-datasource-routing/
了解其使用情况的样本。
答案 4 :(得分:0)
其他一些答案暗示使用两个交易管理器在某种程度上是错误的;但是,Spring的XML配置允许使用在线文档中所述的多个事务管理器(如下所示)。不幸的是,似乎没有办法让@EnableTransactionManagement
注释以类似的方式工作。因此,我只需使用@ImportResource
注释来加载包含<tx:annotation-driven/>
行的XML文件。这允许您为大多数事情获取Java配置,但仍然使用@Transactional
和可选的事务管理器限定符。
http://docs.spring.io/spring/docs/3.1.x/spring-framework-reference/html/transaction.html
大多数Spring应用程序只需要一个事务管理器,但在某些情况下,您可能需要在单个应用程序中使用多个独立的事务管理器。
@Transactional
注释的value属性可用于选择性地指定要使用的PlatformTransactionManager
的标识。这可以是bean名称或事务管理器bean的限定符值。例如,使用限定符表示法,以下Java代码
答案 5 :(得分:0)
尝试使用链接的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 {
....
}
,它将对两个数据库事务管理器进行回滚。
答案 6 :(得分:0)
我必须在一个项目中使用JPA和Reactive Mongo。最后起作用的是:
@Configuraition
类以显式创建一个JPA事务管理器,例如here: private Environment env;
@Bean
@Primary
public LocalContainerEntityManagerFactoryBean dbEntityManager() {
LocalContainerEntityManagerFactoryBean em = new LocalContainerEntityManagerFactoryBean();
em.setDataSource(dbDatasource());
em.setPackagesToScan(new String[]{"projectone.mysql"});
em.setPersistenceUnitName("dbEntityManager");
HibernateJpaVendorAdapter vendorAdapter = new HibernateJpaVendorAdapter();
em.setJpaVendorAdapter(vendorAdapter);
HashMap<String, Object> properties = new HashMap<>();
properties.put("hibernate.dialect",env.getProperty("hibernate.dialect"));
properties.put("hibernate.show-sql",env.getProperty("jdbc.show-sql"));
em.setJpaPropertyMap(properties);
return em;
}
@Primary
@Bean
public DataSource dbDatasource() {
DriverManagerDataSource dataSource
= new DriverManagerDataSource();
dataSource.setDriverClassName(
env.getProperty("spring.datasource.driverClassName"));
dataSource.setUrl(env.getProperty("spring.datasource.url"));
dataSource.setUsername(env.getProperty("spring.datasource.username"));
dataSource.setPassword(env.getProperty("spring.datasource.password"));
return dataSource;
}
@Primary
@Bean
public PlatformTransactionManager jpaTransactionManager() {
JpaTransactionManager transactionManager
= new JpaTransactionManager();
transactionManager.setEntityManagerFactory(
dbEntityManager().getObject());
return transactionManager;
}
}
请注意,bean名称jpaTransactionManager
是JPA @Transactional
中使用的txManager名称。
MongoConfiguration
以显式创建Mongo事务管理器(需要定义很多bean)@Transactional
中,用名字叫他们。默认的transactionManger
将不起作用。您必须像jpaTransactionManager
和reactiveMongoTransactionManger
这样区分。@Transactional(value="jpaTransactionManager")
public void xxx() {
...
}
请注意,JPA事务方法不能将Reactor类型作为返回值(Mono / Flux)。 Spring会强制返回Mono / Flux的方法使用ReactiveTransactionManager,这会引起混乱。