使用MyBatis的Spring:期望的单个匹配bean但找到2
我一直在使用Spring和MyBatis,它对单个数据库的效果非常好。 我在尝试添加另一个数据库时遇到了困难(请参阅Github上的可重复示例 )。
我正在使用Spring Java配置(即不是XML)。 我见过的大多数示例都展示了如何使用XML实现这一点。
我有两个数据配置类(A和B),如下所示:
@Configuration @MapperScan("io.woolford.database.mapper") public class DataConfigDatabaseA { @Bean(name="dataSourceA") public DataSource dataSourceA() throws SQLException { SimpleDriverDataSource dataSource = new SimpleDriverDataSource(); dataSource.setDriver(new com.mysql.jdbc.Driver()); dataSource.setUrl("jdbc:mysql://" + dbHostA + "/" + dbDatabaseA); dataSource.setUsername(dbUserA); dataSource.setPassword(dbPasswordA); return dataSource; } @Bean public SqlSessionFactory sqlSessionFactory() throws Exception { SqlSessionFactoryBean sessionFactory = new SqlSessionFactoryBean(); sessionFactory.setDataSource(dataSourceA()); return sessionFactory.getObject(); } }
两个映射器,以及一个自动assembly映射器的服务:
@Service public class DbService { @Autowired private DbMapperA dbMapperA; @Autowired private DbMapperB dbMapperB; public List getDabaseARecords(){ return dbMapperA.getDatabaseARecords(); } public List getDabaseBRecords(){ return dbMapperB.getDatabaseBRecords(); } }
该应用程序将无法启动:
Error creating bean with name 'dataSourceInitializer': Invocation of init method failed; nested exception is org.springframework.beans.factory.NoUniqueBeanDefinitionException: No qualifying bean of type [javax.sql.DataSource] is defined: expected single matching bean but found 2: dataSourceB,dataSourceA
我已经读过可以使用@Qualifier
注释消除自动assembly的歧义,但我不知道在哪里添加它。
你能看出我哪里出错吗?
如果要同时使用两个数据源且它们不是主数据源和辅助DataSourceAutoConfiguration
, @EnableAutoConfiguration(excludes = {DataSourceAutoConfiguration.class})
在@SpringBootApplication
注释的应用程序上通过@EnableAutoConfiguration(excludes = {DataSourceAutoConfiguration.class})
禁用DataSourceAutoConfiguration
。 之后,您可以创建自己的SqlSessionFactory
并捆绑自己的DataSource
。 如果您还想使用DataSourceTransactionManager
,您也应该这样做。
在这种情况下,您还没有禁用DataSourceAutoConfiguration
,因此spring框架将尝试@Autowired
只有一个DataSource
但是有两个,发生错误。
正如我之前所说,您应该禁用DataSourceAutoConfiguration
并手动配置它。
您可以按如下方式禁用数据源自动配置:
@SpringBootApplication @EnableAutoConfiguration(exclude = {DataSourceAutoConfiguration.class}) public class YourApplication implements CommandLineRunner { public static void main (String... args) { SpringApplication.run(YourApplication.class, args); } }
如果你真的想同时使用多个数据库,我建议你手动注册正确的bean,例如:
package xyz.cloorc.boot.mybatis; import org.apache.commons.dbcp.BasicDataSource; import org.apache.ibatis.session.SqlSessionFactory; import org.mybatis.spring.SqlSessionFactoryBean; import org.mybatis.spring.support.SqlSessionDaoSupport; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.stereotype.Repository; import javax.annotation.PostConstruct; import javax.annotation.Resource; import javax.sql.DataSource; @Configuration public class SimpleTest { private DataSource dsA; private DataSource dsB; @Bean(name = "dataSourceA") public DataSource getDataSourceA() { return dsA != null ? dsA : (dsA = new BasicDataSource()); } @Bean(name = "dataSourceB") public DataSource getDataSourceB() { return dsB != null ? dsB : (dsB = new BasicDataSource()); } @Bean(name = "sqlSessionFactoryA") public SqlSessionFactory getSqlSessionFactoryA() throws Exception { // set DataSource to dsA return new SqlSessionFactoryBean().getObject(); } @Bean(name = "sqlSessionFactoryB") public SqlSessionFactory getSqlSessionFactoryB() throws Exception { // set DataSource to dsB return new SqlSessionFactoryBean().getObject(); } } @Repository public class SimpleDao extends SqlSessionDaoSupport { @Resource(name = "sqlSessionFactoryA") SqlSessionFactory factory; @PostConstruct public void init() { setSqlSessionFactory(factory); } @Override public void setSqlSessionFactory(SqlSessionFactory sqlSessionFactory) { super.setSqlSessionFactory(sqlSessionFactory); } public T get (Object id) { return super.getSqlSession().selectOne("sql statement", "sql parameters"); } }
最后,我们将每个映射器放在自己的文件夹中:
src/main/java/io/woolford/database/mapper/a/DbMapperA.java src/main/java/io/woolford/database/mapper/c/DbMapperB.java
然后,我们创建了两个DataConfig
类,每个数据库对应一个。 @MapperScan
注释解析了expected single matching bean but found 2
问题。
@Configuration @MapperScan(value = {"io.woolford.database.mapper.a"}, sqlSessionFactoryRef="sqlSessionFactoryA") public class DataConfigDatabaseA {
有必要将@Primary
注释添加到其中一个DataConfig
类中的bean:
@Bean(name="dataSourceA") @Primary public DataSource dataSourceA() throws SQLException { ... } @Bean(name="sqlSessionFactoryA") @Primary public SqlSessionFactory sqlSessionFactoryA() throws Exception { ... }
感谢所有帮助过的人。 毫无疑问,这样做的方法不止一种。 我按照@eduardlofitskyi和@GeminiKeith的建议尝试了@Qualifier
和@EnableAutoConfiguration(exclude = {DataSourceAutoConfiguration.class})
,但这又产生了一些错误。
万一它有用,我们的解决方案在这里发布: https : //github.com/alexwoolford/mybatis-spring-multiple-mysql-reproducible-example
您可以使用@Qualifier
注释
问题是你在Spring容器中有两个相同的类型bean。 当你尝试autowire bean时,Spring无法解析哪个bean注入到字段中
@Qualifier
注释是使用限定符的主要方式。 它可以在注入点与@Autowired
或@Inject
一起应用,以指定要注入的bean。
所以,你的DbService应如下所示:
@Service public class DbService { @Autowired @Qualifier("dataSourceA") private DbMapperA dbMapperA; @Autowired @Qualifier("dataSourceB") private DbMapperB dbMapperB; public List getDabaseARecords(){ return dbMapperA.getDatabaseARecords(); } public List getDabaseBRecords(){ return dbMapperB.getDatabaseBRecords(); } }
我有同样的问题,无法启动我的Spring Boot应用程序,并通过重命名有问题的类和处理它的所有层,奇怪的是应用程序启动成功。
我有类UOMService
, UOMServiceImpl
UOMRepository
和UOMRepositoryImpl
。 我将它们重命名为UomService
, UomServiceImpl
, UomRepository
和UomRepositoryImpl
,这解决了这个问题!