1

我们有一个 Spring Boot 应用程序,它应该通过 MyBatis 映射器从两个不同的数据库 DB2 和 Oracle 访问存储过程

我们创建了两个 DB2 上下文类,例如用于 DB2

@Configuration
@MapperScan({ "...mapper.mybatis.db2" })
public class Db2Context {

  @Primary
  @Bean(name = "db2DataSource")
  public DataSource getDataSource() { ...

  @Primary
  @Bean(name = "db2SqlSessionFactory")
  public SqlSessionFactory getSqlSessionFactory() {...

MyBatis bean 看起来像

public interface Db2Mapper extends MyBatisMapper<SomeType> {

  @Override
  @Select(value = ...)
  @Options(statementType = StatementType.CALLABLE)
  @Results({...}) 
  List<SomeType> select(Map<String, Object> parameters);

并且 SqlSessionFactory bean 被注入到具有适当资格的相应 DAO 类中,例如

@Repository
public class Db2Dao {

  @Autowired
  @Qualifier("db2SqlSessionFactory")
  SqlSessionFactory sqlSessionFactory;

  ...

  try(SqlSession session= sqlSessionFactory.openSession(true);) {
    Db2Mapper mapper = session.getMapper(Db2Mapper.class);
    resultSet = mapper.select(parameters);

对于 Oracle,我们也有相同的配置、映射器和 DAO,除了在该配置中 DataSource 和 SqlSessionFactory bean 没有使用 @Primary 注释。根据 Spring Boot 参考中的描述,这是必要的:http: //docs.spring.io/spring-boot/docs/1.2.3.RELEASE/reference/htmlsingle/#howto-two-datasources;否则,Spring Boot 应用程序启动将导致 NoUniqueBeanDefinitionException

使用此配置,Spring Boot 应用程序成功启动,并且在启动期间甚至有 INFO 日志打印输出表明两个映射器类都已成功识别

INFO BeanPostProcessorChecker : Bean 'db2Mapper' of type [class org.mybatis.spring.mapper.MapperFactoryBean] is not eligible for getting processed by all BeanPostProcessors (for example: not eligible for auto-proxying)
INFO BeanPostProcessorChecker : Bean 'oracleMapper' of type [class org.mybatis.spring.mapper.MapperFactoryBean] is not eligible for getting processed by all BeanPostProcessors (for example: not eligible for auto-proxying)

但是,在运行时我们有一个问题。首先执行 Db2Dao,然后一切顺利,DB2 存储过程开始执行,检索到的结果通过 Db2Mapper 存储。然后是 OracleDao;但是在 Oracle SP 执行之后,收到以下异常

ERROR Servlet.service() for servlet [dispatcherServlet] in context with path [] threw exception 
[Request processing failed; ... Type interface com....mapper.mybatis.oracle.OracleMapper is not 
known to the MapperRegistry.]

我们一直在与这个问题斗争一段时间,但找不到解决方案。可能@Primary 的使用可能与它有关,但没有它我们甚至无法启动应用程序。我们的研究实际上似乎表明不同的库版本甚至可能提供不同的行为:我们的堆栈是 Java 1.8、Spring Boot 1.2.6、Spring 4.1.7、MyBatis 3.2.5、MyBatis-Spring 1.2.2

4

1 回答 1

2

首先,我建议根本不要自动装配SqlSessionFactory到您的 DAO 中。事实上,您可以完全摆脱 DAO,并将服务层中的映射器用作 spring bean。

所以你做这样的事情:

public interface Db2Mapper extends MyBatisMapper<SomeType> {

  @Override
  @Select(value = ...)
  @Options(statementType = StatementType.CALLABLE)
  @Results({...}) 
  List<SomeType> select(Map<String, Object> parameters);
}

@Service
public class Db2Service{
  @Autowired
  private Db2Mapper db2Mapper;

  //...
}

其次,mybatis-spring集成各种数据源的关键在于注解的sqlSessionFactoryRef属性。@MapperScan有了它,您可以缩小SqlSessionFactory用于 witch 的实例@MapperScan。像这样的东西:

@Configuration
@MapperScan(value = { "...mapper.mybatis.db2" }, sqlSessionFactoryRef = "db2SqlSessionFactory")
public class Db2Context {

  @Primary
  @Bean(name = "db2DataSource")
  public DataSource getDataSource() { ...

  @Primary
  @Bean(name = "db2SqlSessionFactory")
  public SqlSessionFactory getSqlSessionFactory() {...

@Configuration
@MapperScan(value = { "...mapper.mybatis.other" }, sqlSessionFactoryRef = "otherSqlSessionFactory")
public class OtherContext {

  @Bean(name = "otherDataSource")
  public DataSource getDataSource() { ...

  @Bean(name = "otherSqlSessionFactory")
  public SqlSessionFactory getSqlSessionFactory() {...

显然,您不应该使用这两个 @MapperScan 注释扫描相同的包。

于 2015-12-23T12:40:53.557 回答