背景: mybatis-plus + 多数据源启动项目一直报错:
2024-02-22 14:31:20,298-WARN-[AbstractApplicationContext.java:591]-[main]-Exception encountered during context initialization - cancelling refresh attempt: org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'accountController': Unsatisfied dependency expressed through field 'userService'; nested exception is org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'userService': Unsatisfied dependency expressed through field 'baseMapper'; nested exception is org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'IUserDAO' defined in file [D:\Epson\vipwp-springboot2\target\classes\com\epson\vipwp\dao\IUserDAO.class]: Unsatisfied dependency expressed through bean property 'sqlSessionTemplate'; nested exception is org.springframework.beans.factory.NoUniqueBeanDefinitionException: No qualifying bean of type 'org.mybatis.spring.SqlSessionTemplate' available: expected single matching bean but found 4: sqlSessionTemplate,sqlSessionTemplatePop,sqlSessionTemplateOqc,sqlSessionTemplateQpost
2024-02-22 14:31:20,303-INFO-[DirectJDKLog.java:173]-[main]-Stopping service [Tomcat]
2024-02-22 14:31:20,351-ERROR-[LoggingFailureAnalysisReporter.java:40]-[main]-***************************
APPLICATION FAILED TO START
***************************Description:
file [D:\Epson\vipwp-springboot2\target\classes\com\epson\vipwp\dao\IUserDAO.class] required a single bean, but 4 were found:
- sqlSessionTemplate: defined by method 'sqlSessionTemplateAssy' in class path resource [com/epson/vipwp/core/DataSourceConfig.class]
- sqlSessionTemplatePop: defined by method 'sqlSessionTemplatePop' in class path resource [com/epson/vipwp/core/DataSourceConfig.class]
- sqlSessionTemplateOqc: defined by method 'sqlSessionTemplateOqc' in class path resource [com/epson/vipwp/core/DataSourceConfig.class]
- sqlSessionTemplateQpost: defined by method 'sqlSessionTemplateQpost' in class path resource [com/epson/vipwp/core/DataSourceConfig.class]
Action:Consider marking one of the beans as @Primary, updating the consumer to accept multiple beans, or using @Qualifier to identify the bean that should be consumed
也就是找到4个 sqlSessionTemplate因此mybatis plus不知道该使用哪个数据源,
网上各种找解决办法都是说在
@Bean(name = "sqlSessionFactory")的定义上面添加@Primary标签,当不在service上面使用@DS注解时就使用@Primary标签定义的默认的数据源,但是无效,后来尝试了在
@Bean(name = "sqlSessionTemplate")的上面添加@Primary注解,居然神奇的解决了
以下是完整的4个数据源配置:
package com.xxx;
import org.apache.ibatis.session.SqlSessionFactory;
import org.mybatis.spring.SqlSessionFactoryBean;
import org.mybatis.spring.SqlSessionTemplate;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.boot.jdbc.DataSourceBuilder;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;
import org.springframework.jdbc.core.JdbcTemplate;
import javax.sql.DataSource;
import java.util.Objects;
/**
* 数据源配置类
*/
@Configuration
public class DataSourceConfig {
//以下四个DataSource不能定义在这,否则将循环引用,springboot无法启动
// @Autowired private DataSource dataSourceAssy; // 装配ASSY数据源 ---//省略后面几个,反正也不能定义
//貌似后面3个SqlSessionFactory根本没有被用到,因此注释掉
// 定义ASSY数据源相关的Bean
// 使用@Primary注解表示当存在多个同类型的Bean时,优先选择该Bean
@Primary
@Bean(name = "dataSourceAssy")
@ConfigurationProperties(prefix = "spring.datasource.assy")
public DataSource dataSourceAssy() {
return DataSourceBuilder.create().build();
} // 使用DataSourceBuilder创建数据源
@Primary // 指定为默认jdbcTemplateAssy
@Bean(name = "jdbcTemplateAssy")
public JdbcTemplate jdbcTemplateAssy(@Qualifier("dataSourceAssy") DataSource dataSource) {
return new JdbcTemplate(dataSource); // 创建JdbcTemplate实例,用于执行SQL操作
}
@Primary // 指定为默认SqlSessionFactory
@Bean(name = "sqlSessionFactory") //默认数据源不能乱起名字,必须叫sqlSessionFactory
public SqlSessionFactory sqlSessionFactoryAssy(@Qualifier("dataSourceAssy") DataSource dataSource) throws Exception {
SqlSessionFactoryBean factory = new SqlSessionFactoryBean();// 创建SqlSessionFactoryBean实例
factory.setDataSource(dataSource);// 设置数据源
// 加载mybatis的相关配置文件,如果有的话
// factoryBean.setConfigLocation(new ClassPathResource("mybatis-config.xml"));
// 设置实体类别名包扫描
factory.setTypeAliasesPackage("com.epson.vipwp.domain");
// 添加 SqlSessionTemplate Bean 的定义
SqlSessionTemplate sqlSessionTemplate = new SqlSessionTemplate(Objects.requireNonNull(factory.getObject()));
return factory.getObject();// 返回SqlSessionFactory实例,用于创建SqlSession,使用SqlSession调用sql时不需要指定数据源,因为就在此处指定了
}
//如果要将 SqlSessionTemplate 作为单独的 Bean 注入,可以这样:
@Primary
@Bean(name = "sqlSessionTemplate")
public SqlSessionTemplate sqlSessionTemplateAssy(SqlSessionFactory sqlSessionFactoryAssy) {
return new SqlSessionTemplate(sqlSessionFactoryAssy);
}
//POP
@Bean(name = "dataSourcePop")
@ConfigurationProperties(prefix = "spring.datasource.pop")
public DataSource dataSourcePop() {
return DataSourceBuilder.create().build();
}// 使用DataSourceBuilder创建POP数据源
@Bean(name = "jdbcTemplatePop")
public JdbcTemplate jdbcTemplatePop(@Qualifier("dataSourcePop") DataSource dataSource) {
return new JdbcTemplate(dataSource);// 创建POP JdbcTemplate实例,用于执行SQL操作
}
@Bean(name = "sqlSessionFactoryPop")
public SqlSessionFactory sqlSessionFactoryPop(@Qualifier("dataSourcePop") DataSource dataSource) throws Exception {
SqlSessionFactoryBean factory = new SqlSessionFactoryBean();// 创建SqlSessionFactoryBean实例
factory.setDataSource(dataSource);// 设置数据源
factory.setTypeAliasesPackage("com.epson.vipwp.domain");
// 添加 SqlSessionTemplate Bean 的定义
SqlSessionTemplate sqlSessionTemplate = new SqlSessionTemplate(Objects.requireNonNull(factory.getObject()));
return factory.getObject();// 返回SqlSessionFactory实例,用于创建SqlSession,使用SqlSession调用sql时不需要指定数据源,因为就在此处指定了
}
//如果要将 SqlSessionTemplate 作为单独的 Bean 注入,可以这样:
@Bean(name = "sqlSessionTemplatePop")
public SqlSessionTemplate sqlSessionTemplatePop(SqlSessionFactory sqlSessionFactoryPop) {
return new SqlSessionTemplate(sqlSessionFactoryPop);
}
//OQC
@Bean(name = "dataSourceOqc")
@ConfigurationProperties(prefix = "spring.datasource.oqc")
public DataSource dataSourceOqc() {
return DataSourceBuilder.create().build();
}
@Bean(name = "jdbcTemplateOqc")
public JdbcTemplate jdbcTemplateOqc(@Qualifier("dataSourceOqc") DataSource dataSource) {
return new JdbcTemplate(dataSource);
}
@Bean(name = "sqlSessionFactoryOqc")
public SqlSessionFactory sqlSessionFactoryOqc(@Qualifier("dataSourceOqc") DataSource dataSource) throws Exception {
SqlSessionFactoryBean factory = new SqlSessionFactoryBean();// 创建SqlSessionFactoryBean实例
factory.setDataSource(dataSource);// 设置数据源
factory.setTypeAliasesPackage("com.epson.vipwp.domain");
// 添加 SqlSessionTemplate Bean 的定义
SqlSessionTemplate sqlSessionTemplate = new SqlSessionTemplate(Objects.requireNonNull(factory.getObject()));
return factory.getObject();// 返回SqlSessionFactory实例,用于创建SqlSession,使用SqlSession调用sql时不需要指定数据源,因为就在此处指定了
}
//如果要将 SqlSessionTemplate 作为单独的 Bean 注入,可以这样:
@Bean(name = "sqlSessionTemplateOqc")
public SqlSessionTemplate sqlSessionTemplateOqc(SqlSessionFactory sqlSessionFactoryOqc) {
return new SqlSessionTemplate(sqlSessionFactoryOqc);
}
//qpost
@Bean(name = "dataSourceQpost")
@ConfigurationProperties(prefix = "spring.datasource.qpost")
public DataSource dataSourceQpost() {
return DataSourceBuilder.create().build();
}
@Bean(name = "jdbcTemplateQpost")
public JdbcTemplate jdbcTemplateQpost(@Qualifier("dataSourceQpost") DataSource dataSource) {
return new JdbcTemplate(dataSource);
}
@Bean(name = "sqlSessionFactoryQpost")
public SqlSessionFactory sqlSessionFactoryQpost(@Qualifier("dataSourceQpost") DataSource dataSource) throws Exception {
SqlSessionFactoryBean factory = new SqlSessionFactoryBean();// 创建SqlSessionFactoryBean实例
factory.setDataSource(dataSource);// 设置数据源
factory.setTypeAliasesPackage("com.epson.vipwp.domain");
// 添加 SqlSessionTemplate Bean 的定义
SqlSessionTemplate sqlSessionTemplate = new SqlSessionTemplate(Objects.requireNonNull(factory.getObject()));
return factory.getObject();// 返回SqlSessionFactory实例,用于创建SqlSession,使用SqlSession调用sql时不需要指定数据源,因为就在此处指定了
}
//如果要将 SqlSessionTemplate 作为单独的 Bean 注入,可以这样:
@Bean(name = "sqlSessionTemplateQpost")
public SqlSessionTemplate sqlSessionTemplateQpost(SqlSessionFactory sqlSessionFactoryQpost) {
return new SqlSessionTemplate(sqlSessionFactoryQpost);
}
}
如果要使用jdbcTemplate,那么也需要在4个中添加@Primary,否则也会报错,不然就是使用哪个jdbc指明才行