2016-03-23 3 views
4

Я использую Spring с MyBatis, и он отлично работает для одной базы данных. Я столкнулся с трудностями при попытке добавить другую базу данных (см. reproducible example on Github).Весна с MyBatis: ожидаемый единственный совпадающий компонент, но найден 2

Я использую конфигурацию 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(); 
    } 
} 

Два мапперы и услуги, которые autowires картостроителей:

@Service 
public class DbService { 

    @Autowired 
    private DbMapperA dbMapperA; 

    @Autowired 
    private DbMapperB dbMapperB; 

    public List<Record> getDabaseARecords(){ 
     return dbMapperA.getDatabaseARecords(); 
    } 

    public List<Record> 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, чтобы устранить автоувеличивание, хотя я не был уверен, где его добавить.

Вы видите, куда я иду не так?

+0

Вы можете публиковать полное сообщение об ошибке? Обычно весна сообщает вам поле с автопроводом и фасоль, вызывающую ошибку. – ben75

+0

'@Qaulifier (« name_of_bean »)' может быть размещен до или после аннотации '@ Autowired' конкретного поля, на которое вы хотите нацелиться. Я считаю, – BretC

+0

Спасибо @ Ben75. Я опубликовал полный вывод: https://gist.github.com/alexwoolford/1f3e799deb3be32a4356 –

ответ

1

В конце концов, мы помещаем каждый картографа в своей папке:

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(name="dataSourceA") 
@Primary 
public DataSource dataSourceA() throws SQLException { 
    ... 
} 

@Bean(name="sqlSessionFactoryA") 
@Primary 
public SqlSessionFactory sqlSessionFactoryA() throws Exception { 
    ... 
} 

Спасибо всем, кто помог. Несомненно, есть более чем один способ сделать это. Я попробовал @Qualifier и @EnableAutoConfiguration(exclude = {DataSourceAutoConfiguration.class}) в соответствии с рекомендациями @eduardlofitskyi и @GeminiKeith, но это породило некоторые дополнительные ошибки.

В случае, если это полезно, то решение, которое работало для нас размещено здесь: https://github.com/alexwoolford/mybatis-spring-multiple-mysql-reproducible-example

2

Если вы хотите использовать два источника данных в одно и то же время, и они не являются первичными и вторичными, вы должны отключить DataSourceAutoConfiguration от @EnableAutoConfiguration(excludes = {DataSourceAutoConfiguration.class}) в своем приложении, аннотированное @SpringBootApplication. Впоследствии вы можете создать свой собственный SqlSessionFactory и расслоить свой собственный DataSource. Если вы также хотите использовать DataSourceTransactionManager, вы должны это сделать.

В этом случае вы не отключили DataSourceAutoConfiguration, поэтому весенний каркас попытается установить @Autowired только один DataSource, но получил две ошибки.

Как я уже говорил, вы должны отключить DataSourceAutoConfiguration и настроить его вручную.

Вы можете отключить автоматическую конфигурацию источника данных следующим образом:

@SpringBootApplication 
@EnableAutoConfiguration(exclude = {DataSourceAutoConfiguration.class}) 
public class YourApplication implements CommandLineRunner { 
    public static void main (String... args) { 
     SpringApplication.run(YourApplication.class, args); 
    } 
} 

И если вы действительно хотите использовать несколько баз данных, в то же время, я предлагаю вам регистрации надлежащего боб вручную, например:

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> T get (Object id) { 
     return super.getSqlSession().selectOne("sql statement", "sql parameters"); 
    } 
} 
+0

Какой полезный ответ !!! Или '@EnableAutoConfiguration (исключает = DataSourceAutoConfiguration.class)' или '@SpringBootApplication (exclude = DataSourceAutoConfiguration.class)'. – sjngm

+0

Спасибо! потратил на это час! –

0

вы можете использовать @Qualifier аннотацию

проблема заключается в том, что у вас есть две одинаковые бобы типа в Spring контейнере. И когда вы пытаетесь использовать autowire beans, Spring не может решить, какой bean-инъекция вводить в поле

Аннотации @Qualifier - это основной способ работы с квалификаторами. Его можно применять рядом с @Autowired или @Inject в точке инъекции, чтобы указать, какой компонент вы хотите ввести.

Итак, ваш DbService должен выглядеть следующим образом:

@Service 
    public class DbService { 

    @Autowired 
    @Qualifier("dataSourceA") 
    private DbMapperA dbMapperA; 

    @Autowired 
    @Qualifier("dataSourceB") 
    private DbMapperB dbMapperB; 

    public List<Record> getDabaseARecords(){ 
     return dbMapperA.getDatabaseARecords(); 
    } 

    public List<Record> getDabaseBRecords(){ 
     return dbMapperB.getDatabaseBRecords(); 
    } 

} 
0

Я была такая же проблема и не могу начать свое Spring приложения загрузки, и переименовав класс обижая и все слои, которые касаются с ним, как ни странно, приложение успешно запущено.

У меня есть классы UOMService, UOMServiceImplUOMRepository и UOMRepositoryImpl. Я переименовал их в UomService, UomServiceImpl, UomRepository и UomRepositoryImpl, и это решило проблему!

 Смежные вопросы

  • Нет связанных вопросов^_^