mybatis-plus多数据源事务报错 No qualifying bean of type ‘org.springframework.transaction.TransactionManager‘

项目中使用了多数据源配置,在添加事务的时候,出现了如下异常

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(Collection<T> entityList) {
        return this.saveBatch(entityList, 1000);
    }
找到原因了,因为是公共方法,所以不会指定事务管理器,使用的是默认管理器,但我在代码中没有告诉spring哪个数据源的事务管理器才是默认的,所以就一直在报错.弄明白了这层原因,那就方便了,就是添加一个默认事务管理就可以了.

使用第三方jar包方便是方便了.但一定要弄明白你调用的方法是如何去运行的,不然就会像我一样,为一个本来很明显的问题困扰很久很久.

  • 10
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值