问题重现
步骤
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文件
所以需要找出来,读取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 方法中
读取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)
设置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
若想亲自调试,可以关注如下类:
- org.mybatis.spring.boot.autoconfigure.MybatisAutoConfiguration
- org.mybatis.spring.SqlSessionFactoryBean
- org.apache.ibatis.session.SqlSessionFactoryBuilder