1. 情况描述
分析过程可以直接跳过,直接看解决方法
在只引入了一个xml目录时,程序运行正常,各个Mapper方法也可以正常调用,后续其它开发同志引入了其他包中的xml目录,导致调用Mapper的所有方法都报错,最后没找到原因也没解决,然后交给了我解决。
版本信息:
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.5.1</version>
<relativePath/>
</parent>
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-boot-starter</artifactId>
<version>3.5.1</version>
</dependency>
yml中原mybatis配置:
mybatis:
mapper-locations: classpath*:/mapper/**/*.xml
引入其它包后的配置:
mybatis:
mapper-locations: classpath*:/mapper/**/*.xml, classpath*:/xmls/**/*.xml
mybatis-plus配置类:
@Configuration
public class MybatisPlusConfig {
@Value("${mybatis-plus.mapper-locations}")
private String mapperLocations;
@Bean
public SqlSessionFactory sqlSessionFactory(DataSource dataSource)
throws Exception {
final MybatisSqlSessionFactoryBean sessionFactory = new MybatisSqlSessionFactoryBean();
sessionFactory.setDataSource(dataSource);
sessionFactory.setMapperLocations(new PathMatchingResourcePatternResolver().getResources(mapperLocations));
// 设置公共字段的拦截
GlobalConfig globalConfig = GlobalConfigUtils.defaults();
sessionFactory.setGlobalConfig(globalConfig);
return sessionFactory.getObject();
}
}
2. 报错信息
org.apache.ibatis.binding.BindingException: Invalid bound statement (not found): cn.mmd.orm.mapper.health.HealthRecordsMapper.selectRecords
at org.apache.ibatis.binding.MapperMethod$SqlCommand.<init>(MapperMethod.java:235) ~[mybatis-3.5.10.jar:3.5.10]
at com.baomidou.mybatisplus.core.override.MybatisMapperMethod.<init>(MybatisMapperMethod.java:50) ~[mybatis-plus-core-3.5.2.jar:3.5.2]
at com.baomidou.mybatisplus.core.override.MybatisMapperProxy.lambda$cachedInvoker$0(MybatisMapperProxy.java:111) ~[mybatis-plus-core-3.5.2.jar:3.5.2]
at java.util.concurrent.ConcurrentHashMap.computeIfAbsent(ConcurrentHashMap.java:1660) ~[?:1.8.0_171]
at com.baomidou.mybatisplus.core.toolkit.CollectionUtils.computeIfAbsent(CollectionUtils.java:115) ~[mybatis-plus-core-3.5.2.jar:3.5.2]
at com.baomidou.mybatisplus.core.override.MybatisMapperProxy.cachedInvoker(MybatisMapperProxy.java:98) ~[mybatis-plus-core-3.5.2.jar:3.5.2]
at com.baomidou.mybatisplus.core.override.MybatisMapperProxy.invoke(MybatisMapperProxy.java:89) ~[mybatis-plus-core-3.5.2.jar:3.5.2]
at com.sun.proxy.$Proxy136.selectRecordByIdCardNumber(Unknown Source) ~[?:?]
……
- 看到这个报错的时候,我第一时间怀疑是不是yml中的classpath地址写错了,检查发现没得问题。之前可以运行成功就证明Mapper.xml中的namespace写错或者方法名写错等问题是不存在的,这里不考虑。
mybatis:
mapper-locations: classpath*:/mapper/**/*.xml, classpath*:/xmls/**/*.xml
- 然后有怀疑是新加的classpath没有扫描成功,检查pom配置后发现是有扫描所有xml文件的:
<resources>
<resource>
<directory>src/main/resources</directory>
<includes>
<include>**/*.yml</include>
<include>**/*.xml</include>
<include>**/*.properties</include>
</includes>
<filtering>true</filtering>
</resource>
</resources>
-
随后查看jar包中也有mapper和xmls对应的jar包和他们的xml文件。
到这里其实就很疑惑,之前从来没碰到过这种问题,网上搜索一番后也没什么新发现。
-
没法只能打断点看看哪里出了问题,最后发现是MybatisPlusConfig配置类扫描资源的问题:
new PathMatchingResourcePatternResolver().getResources(mapperLocations)这个类扫描xml资源的时候,一条资源也没返回。这下找到原因了,最后点进源码查看,才发现这一个版本资源扫描根本就没有处理多资源的情况!!!!
根目录只识别了mapper这个文件夹,文件的匹配模式直接就截取了根目录后面的所有内容:
**/*.xml,classpath*:/xmls/**/*.xml
这下找到原因就好办了,进入解决问题模式。
3. 解决方法
手动加载多个xml资源
@Bean
public SqlSessionFactory sqlSessionFactory(DataSource dataSource)
throws Exception {
final MybatisSqlSessionFactoryBean sessionFactory = new MybatisSqlSessionFactoryBean();
sessionFactory.setDataSource(dataSource);
// 多mapper地址手动加载
PathMatchingResourcePatternResolver resourcePatternResolver = new PathMatchingResourcePatternResolver();
String[] split = mapperLocations.split(",");
Resource[] resources = resourcePatternResolver.getResources(split[0]);
Resource[] resources1 = resourcePatternResolver.getResources(split[1]);
// 合并两个mapper资源
sessionFactory.setMapperLocations(ArrayUtil.addAll(resources, resources1));
// 设置公共字段的拦截
GlobalConfig globalConfig = GlobalConfigUtils.defaults();
sessionFactory.setGlobalConfig(globalConfig);
return sessionFactory.getObject();
}