项目中使用了多数据源配置,在添加事务的时候,出现了如下异常
No qualifying bean of type 'org.springframework.transaction.TransactionManager' available
这个是因为找不到对应的事务管理器报出的错误.网上有很多种方法,其实已经说的很明确了.
就是给自己配置的数据源,分别添加各自的事务管理,然后在使用事务的地方注明自己的事务管理
数据源配置时,添加自己的事务管理
@Bean(name = "middleDataSourceDruid") @ConfigurationProperties("spring.datasource.middle-druid") public DataSource middleDataSourceDruid() { return DruidDataSourceBuilder.create().build(); } @Bean(name = "midDataSourceTransactionManager") public PlatformTransactionManager midDataSourceTransactionManager(@Qualifier("middleDataSourceDruid") DataSource dataSource) { return new DataSourceTransactionManager(dataSource); }
使用事务时,通过value指定事务管理器
@Transactional(rollbackFor = Exception.class,value = "midDataSourceTransactionManager")
这样就可以解决这个报错.
但有一些特殊情况,由于我在项目中使用的是mybatis-plus.调用公共方法saveBatch()时,还是会报错,说找不到事务管理器.(有时候也报找到多个)但是调用save()方法就不会有这个问题.这个就很尴尬了.在网上找了找.没有找到解决办法.只能自己去跟源码找了
事务管理器的选择主要看
TransactionAspectSupport 类下的这个方法determineTransactionManager
@Nullable protected Object invokeWithinTransaction(Method method, @Nullable Class> targetClass, final InvocationCallback invocation) throws Throwable { // If the transaction attribute is null, the method is non-transactional. TransactionAttributeSource tas = getTransactionAttributeSource(); final TransactionAttribute txAttr = (tas != null ? tas.getTransactionAttribute(method, targetClass) : null); final TransactionManager tm = determineTransactionManager(txAttr);
跟进去可以发现
// Do not attempt to lookup tx manager if no tx attributes are set if (txAttr == null || this.beanFactory == null) { return getTransactionManager(); } String qualifier = txAttr.getQualifier(); if (StringUtils.hasText(qualifier)) { return determineQualifiedTransactionManager(this.beanFactory, qualifier); } else if (StringUtils.hasText(this.transactionManagerBeanName)) { return determineQualifiedTransactionManager(this.beanFactory, this.transactionManagerBeanName); } else { TransactionManager defaultTransactionManager = getTransactionManager(); if (defaultTransactionManager == null) { defaultTransactionManager = this.transactionManagerCache.get(DEFAULT_TRANSACTION_MANAGER_KEY); if (defaultTransactionManager == null) { defaultTransactionManager = this.beanFactory.getBean(TransactionManager.class); this.transactionManagerCache.putIfAbsent( DEFAULT_TRANSACTION_MANAGER_KEY, defaultTransactionManager); } } return defaultTransactionManager; }
有这么一行代码
String qualifier = txAttr.getQualifier();
这里是获取@Transactional 中的value值,然后通过值去获取对应的事务管理器.如果为空值,就会去获取默认的事务管理器.但我再在配置多数据源的事务管理器时,没有告诉spring,谁才是默认的,然后就会报错No qualifying bean of type 'org.springframework.transaction.TransactionManager',有的方法就是直接在配置事务管理器时,添加@Primary,来指定默认事务管理器.
@Bean(name = "midDataSourceTransactionManager") @Primary public PlatformTransactionManager midDataSourceTransactionManager(@Qualifier("middleDataSourceDruid") DataSource dataSource) { return new DataSourceTransactionManager(dataSource); }
但我每个事务都指定了由谁来处理事务,为什么还会去找默认的事务管理器呢?这就让我很不明白,而且跟中代码,发现qualifier的值也是对的,也找到了事务管理器.但还是报错.有点抓狂.
正在焦急中,我突然发现,在调用saveBatch()方法时,String qualifier = txAttr.getQualifier();这行的断点进去了两次,在第二次的时候,值为 "" (空字符串),也就是没有指定事务管理器,然后去找默认的,就报错了.然后进入saveBatch()方法一看,才明白,原来saveBatch()方法上还有一个@Transactional,且value没有赋值.
@Transactional( rollbackFor = {Exception.class} ) default boolean saveBatch(CollectionentityList) { return this.saveBatch(entityList, 1000); }
找到原因了,因为是公共方法,所以不会指定事务管理器,使用的是默认管理器,但我在代码中没有告诉spring哪个数据源的事务管理器才是默认的,所以就一直在报错.弄明白了这层原因,那就方便了,就是添加一个默认事务管理就可以了.
使用第三方jar包方便是方便了.但一定要弄明白你调用的方法是如何去运行的,不然就会像我一样,为一个本来很明显的问题困扰很久很久.
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)