问题背景
使用插件 mybatisX 生成的 mapper.xml 没有办法被正常解析,项目使用的是 nacos 作为配置中心;问题定位
1. 首先看了一下网上说的常见几种问题,比如 id 不匹配,或者说 pom 里缺少 resource 配置导致 target 里没有 xml;这些都没有出现; 2. 那接下来就只能从源码出发解决问题; 3. 通过报错的堆栈信息我发现问题的出发点是在这里 public SqlCommand(Configuration configuration, Class<?> mapperInterface, Method method) {
final String methodName = method.getName();
final Class<?> declaringClass = method.getDeclaringClass();
MappedStatement ms = resolveMappedStatement(mapperInterface, methodName, declaringClass,
configuration);
if (ms == null) {
if (method.getAnnotation(Flush.class) != null) {
name = null;
type = SqlCommandType.FLUSH;
} else {
throw new BindingException("Invalid bound statement (not found): "
+ mapperInterface.getName() + "." + methodName);
}
} else {
name = ms.getId();
type = ms.getSqlCommandType();
if (type == SqlCommandType.UNKNOWN) {
throw new BindingException("Unknown execution method for: " + name);
}
}
}
ms == null 这个判断返回了 true,因此我们继续看 resolveMappedStatement 这个方法为什么会出现 null;
private MappedStatement resolveMappedStatement(Class<?> mapperInterface, String methodName,
Class<?> declaringClass, Configuration configuration) {
String statementId = mapperInterface.getName() + "." + methodName;
if (configuration.hasStatement(statementId)) {
return configuration.getMappedStatement(statementId);
} else if (mapperInterface.equals(declaringClass)) {
return null;
}
for (Class<?> superInterface : mapperInterface.getInterfaces()) {
if (declaringClass.isAssignableFrom(superInterface)) {
MappedStatement ms = resolveMappedStatement(superInterface, methodName,
declaringClass, configuration);
if (ms != null) {
return ms;
}
}
}
return null;
}
这里面是 configuration 中的mappedStatements中我想要的 sql 方法不存在;这时候我就怀疑我的 xml 解析因为没有正确被解析器解析导致了问题的出现;
接下来看这个类MybatisPlusAutoConfiguration.java,这个类里的这个构造方法提供了 xml 的解析能力;
@Bean
@ConditionalOnMissingBean
public SqlSessionFactory sqlSessionFactory(DataSource dataSource)
// 中间省略不必要的行
Resource[] mapperLocations = this.properties.resolveMapperLocations();
if (!ObjectUtils.isEmpty(mapperLocations)) {
factory.setMapperLocations(mapperLocations);
}
我打上断点,重启项目;结果发现根本没有走到断点这里;也就是说 xml 解析能力根本没有派上用场;
接下来问题的关键就昭然若揭了;因为这个类有@Bean ,如果没有初始化说明有其他的 bean 覆盖了这个代码块的初始化逻辑;在项目里全局搜索SqlSeesionFactory,果然找到一块定义 bean 的代码;
最后解决方式就是在这个自定义 bean 的方法里面,补上 MapperLocations 的赋值逻辑;
@Bean
public SqlSessionFactory sqlSessionFactory(DataSource dataSource) throws Exception {
MybatisSqlSessionFactoryBean factory = new MybatisSqlSessionFactoryBean();
factory.setDataSource(dataSource);
ResourcePatternResolver resolver = new PathMatchingResourcePatternResolver();
factory.setMapperLocations(resolver.getResources(mapperLocations));
return factory.getObject();
}