记一次mybatis bindingexception 问题排查

Posted 鹊南

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了记一次mybatis bindingexception 问题排查相关的知识,希望对你有一定的参考价值。

看到的错误信息如出一辙都是这样的:Method threw \'org.apache.ibatis.binding.BindingException\' exception.Invalid bound statement (not found): **.dao.**Dao.select

1.考虑返回值类型是否不匹配,一顿修改,@Results 也使用到。 最终无果。

2.开始各种百度,先申明本人使用的方式注解方式, 并非最常用的xml方式。 百度内容大都雷同,检查包名,类名,方法名 是否映射。无果。

3.由于 mybatis 报的错误,不是很明确。 无奈只能debug 源码。

4. 查看更为详细的异常日志

 1 org.apache.ibatis.binding.BindingException: Invalid bound statement (not found): com.sankuai.meituan.banma.thrift.activity.admin.dao.CouponPossessDao.selectUnusedPageNum
 2     at org.apache.ibatis.binding.MapperMethod$SqlCommand.<init>(MapperMethod.java:214) ~[mybatis-3.4.0.jar:3.4.0]
 3     at org.apache.ibatis.binding.MapperMethod.<init>(MapperMethod.java:48) ~[mybatis-3.4.0.jar:3.4.0]
 4     at org.apache.ibatis.binding.MapperProxy.cachedMapperMethod(MapperProxy.java:59) ~[mybatis-3.4.0.jar:3.4.0]
 5     at org.apache.ibatis.binding.MapperProxy.invoke(MapperProxy.java:52) ~[mybatis-3.4.0.jar:3.4.0]
 6     at com.sun.proxy.$Proxy96.selectUnusedPageNum(Unknown Source) ~[na:na]
 7     at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[na:1.8.0_131]
 8     at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) ~[na:1.8.0_131]
 9     at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[na:1.8.0_131]
10     at java.lang.reflect.Method.invoke(Method.java:498) ~[na:1.8.0_131]
11     at com.dianping.zebra.dao.AsyncMapperProxy.invoke(AsyncMapperProxy.java:64) ~[zebra-dao-0.2.4.jar:na]
12     at com.sun.proxy.$Proxy96.selectUnusedPageNum(Unknown Source) ~[na:na]

第二行是重点。点击查看代码。

 1  public SqlCommand(Configuration configuration, Class<?> mapperInterface, Method method) {
 2             String statementName = mapperInterface.getName() + "." + method.getName();
 3             MappedStatement ms = null;
 4             if(configuration.hasStatement(statementName)) { //正常的逻辑都会进入该 if 逻辑,然后得到ms。 该方法未进入该逻辑。不到是该方法初始化时,就失败了。
 5                 ms = configuration.getMappedStatement(statementName);
 6             } else if(!mapperInterface.equals(method.getDeclaringClass())) {
 7                 String parentStatementName = method.getDeclaringClass().getName() + "." + method.getName();
 8                 if(configuration.hasStatement(parentStatementName)) {
 9                     ms = configuration.getMappedStatement(parentStatementName);
10                 }
11             }
12 
13             if(ms == null) {
14                 if(method.getAnnotation(Flush.class) == null) {
15                     throw new BindingException("Invalid bound statement (not found): " + statementName); //该行即为抛出的异常日志
16                 }
17 
18                 this.name = null;
19                 this.type = SqlCommandType.FLUSH;
20             } else {
21                 this.name = ms.getId();
22                 this.type = ms.getSqlCommandType();
23                 if(this.type == SqlCommandType.UNKNOWN) {
24                     throw new BindingException("Unknown execution method for: " + this.name);
25                 }
26             }
27 
28         }

下面开始追踪初始化的代码块。

 1 public class ZebraMapperFactoryBean<T> extends SqlSessionDaoSupport implements FactoryBean<T> {
 2     private Class<T> mapperInterface;
 3     private boolean addToConfig = true;
 4 
 5     public ZebraMapperFactoryBean() {
 6     }
 7 
 8     public void setMapperInterface(Class<T> mapperInterface) {
 9         this.mapperInterface = mapperInterface;
10     }
11 
12     public void setAddToConfig(boolean addToConfig) {
13         this.addToConfig = addToConfig;
14     }
15 
16     protected void checkDaoConfig() {
17         super.checkDaoConfig();
18         Assert.notNull(this.mapperInterface, "Property \'mapperInterface\' is required");
19         Configuration configuration = this.getSqlSession().getConfiguration();
20         if(this.addToConfig && !configuration.hasMapper(this.mapperInterface)) {
21             try {
22                 configuration.addMapper(this.mapperInterface);//下面跟进该方法查询具体的报错行
23             } catch (Throwable var6) {
24                 this.logger.error("Error while adding the mapper \'" + this.mapperInterface + "\' to configuration.", var6); // 初始化时,执行到这里其实已经报错了。但是没影响启动
25                 throw new IllegalArgumentException(var6);
26             } finally {
27                 ErrorContext.instance().reset();
28             }
29         }
30 
31     }


public class MapperAnnotationBuilder {

private SqlSource getSqlSourceFromAnnotations(Method method, Class<?> parameterType, LanguageDriver languageDriver) {
try {
Class<? extends Annotation> sqlAnnotationType = this.getSqlAnnotationType(method);
Class<? extends Annotation> sqlProviderAnnotationType = this.getSqlProviderAnnotationType(method);
Annotation sqlProviderAnnotation;
if(sqlAnnotationType != null) {
if(sqlProviderAnnotationType != null) {
throw new BindingException("You cannot supply both a static SQL and SqlProvider to method named " + method.getName());
} else {
sqlProviderAnnotation = method.getAnnotation(sqlAnnotationType);
String[] strings = (String[])((String[])sqlProviderAnnotation.getClass().getMethod("value", new Class[0]).invoke(sqlProviderAnnotation, new Object[0]));
return this.buildSqlSourceFromStrings(strings, parameterType, languageDriver);
}
} else if(sqlProviderAnnotationType != null) {
sqlProviderAnnotation = method.getAnnotation(sqlProviderAnnotationType);
return new ProviderSqlSource(this.assistant.getConfiguration(), sqlProviderAnnotation);
} else {
return null;
}
} catch (Exception var8) {
throw new BuilderException("Could not find value method on SQL annotation. Cause: " + var8, var8); //最初的报错的位置
}
}

这里就可以找到具体的初始化失败的方法了。

5.至此找到了,正确的解决方案。

6.由此得出几个结论。1.mybatis 报警的确是很不明确。  2.出现问题,优先还是优先考虑排除法。一段代码一段代码检查。 

 

以上是关于记一次mybatis bindingexception 问题排查的主要内容,如果未能解决你的问题,请参考以下文章

记一次源码分析过程,顺便给MyBatis修个Bug

记一次mybatis返回自增主键的低级错误!

记一次使用mybatis进行like 模糊查询遇到的问题

记一次 IDEA mybatis.generator 自定义扩展插件

记一次SpringBoot整合MyBatis时找不到Mapper.xml的BUG定位

记一次IDEA利用mybatis-generator自动生成dao和mapper