自定义SqlSessionFactoryBean导致 mapper-locations 失效

问题重现

步骤
1,把所有的mapper xml移动到 /xxx/yyy/src/main/resources/mybatis/mapperxml 中;
2,修改application.properties ,添加:

mybatis.mapper-locations=classpath:**/mapperxml/*.xml

3,启动springboot 程序 com/test/xxx/app/nnn/Application.java
4,访问接口 http://127.0.0.1:/nnn/productManage/listYYs.json?ccKey=Key222&vvName=%AF%B7%E5%81%87App

报错:

org.apache.ibatis.binding.BindingException: Invalid bound statement (not found):

初步分析

根据现象推断出,spring boot 没有读取我的 mybatis mapper xml文件

自定义SqlSessionFactoryBean导致 mapper-locations 失效

所以需要找出来,读取mybatis mapper xml文件 的逻辑在哪里,为什么没有读取?

定位问题过程

读取mapper xml文件 的逻辑/位置

/repository/org/mybatis/mybatis-spring/1.3.2/mybatis-spring-1.3.2-sources.jar!/org/mybatis/spring/SqlSessionFactoryBean.java的
protected SqlSessionFactory buildSqlSessionFactory() throws IOException 方法中

自定义SqlSessionFactoryBean导致 mapper-locations 失效

读取mapper xml文件的逻辑

if (!isEmpty(this.mapperLocations)) {
      for (Resource mapperLocation : this.mapperLocations) {
        if (mapperLocation == null) {
          continue;
        }
          XMLMapperBuilder xmlMapperBuilder = new XMLMapperBuilder(mapperLocation.getInputStream(),
              configuration, mapperLocation.toString(), configuration.getSqlFragments());
          xmlMapperBuilder.parse();
      }
    } else {
      if (LOGGER.isDebugEnabled()) {
        LOGGER.debug("Property 'mapperLocations' was not specified or no matching resources found");
      }
    }

通过IDEA 调试到这儿的时候,发现 this.mapperLocations 为null,所以才没有走这个逻辑

为什么this.mapperLocations 为null

this.mapperLocations 是在哪里设置的呢?

在 org.mybatis.spring.boot.autoconfigure.MybatisAutoConfiguration 类中,

sqlSessionFactory(DataSource dataSource)

自定义SqlSessionFactoryBean导致 mapper-locations 失效

设置this.mapperLocations的代码:

 if (!ObjectUtils.isEmpty(this.properties.resolveMapperLocations())) {
      factory.setMapperLocations(this.properties.resolveMapperLocations());
    }

之所以没有执行MybatisAutoConfiguration 中的 sqlSessionFactory(DataSource dataSource) throws Exception 方法,是因为

SqlSessionFactoryBean

是我们定制的,没有依赖系统生成.

我们自定义生成SqlSessionFactoryBean 对象

final SqlSessionFactoBean sessionFactoryBean = new SqlSessionFactoBean();

sessionFactoryBean.setDataSource(aaaGroupDataSource);

SqlSessionFactory sqlSessionFactory = sessionFactoryBean.getObject();
// mybatis自动通用字段自动设置配置
org.apache.ibatis.session.Configuration configuration = sqlSessionFactory.getConfiguration();

return sqlSessionFactory;

系统构造SqlSessionFactory

在/repository/org/mybatis/mybatis-spring/1.3.6/mybatis-spring-1.3.6-sources.jar!/org/mybatis/spring/SqlSessionFactoryBean.java 的

protected SqlSessionFactory buildSqlSessionFactory() throws IOException

原因总结

因为我们自定义生成 SqlSessionFactoryBean对象 导致没有执行org.mybatis.spring.boot.autoconfigure.MybatisAutoConfiguration 类的sqlSessionFactory(DataSource dataSource)方法

解决方法

手动添加设置this.mapperLocations 的逻辑即可:

final SqlSessionFactoryBean sessionFactoryBean = new SqlSessionFactoryBean();

//解决 application.properties 中 配置mybatis.mapper-locations 失效的问题
if (!ObjectUtils.isEmpty(this.mybatisProperties.resolveMapperLocations())) {
    sessionFactoryBean.setMapperLocations(this.mybatisProperties.resolveMapperLocations());
}
sessionFactoryBean.setDataSource(aaaGroupDataSource);

SqlSessionFactory sqlSessionFactory = sessionFactoryBean.getObject();
// mybatis自动通用字段自动设置配置
org.apache.ibatis.session.Configuration configuration = sqlSessionFactory.getConfiguration();
// 。。。

return sqlSessionFactory;

//解决 application.properties 中 配置mybatis.mapper-locations 失效的问题

    <span data-type="color" style="color:#F5222D">if (!ObjectUtils.isEmpty(this.mybatisProperties.resolveMapperLocations())) {</span>

sessionFactoryBean.setMapperLocations(this.mybatisProperties.resolveMapperLocations());
}

tips

若想亲自调试,可以关注如下类:

  1. org.mybatis.spring.boot.autoconfigure.MybatisAutoConfiguration
  2. org.mybatis.spring.SqlSessionFactoryBean
  3. org.apache.ibatis.session.SqlSessionFactoryBuilder
上一篇:git push 失败出现error: src refspec master does not match any.解决方案


下一篇:[工作流]一个任务的一辈子