项目使用了mybatis,版本为mybatis-3.2.2.jar + mybatis-spring-1.2.0.jar。今天发现项目运行中出现Invalid bound statement (not found)异常。
mybatis在启动的时候会扫描mapper,把mapper类中的方法及对应的statement语句注册到Configuration对象中。既然出现了Invalid bound statement (not found)异常,说明在运行过程中没有找到对应mapper中的方法。我们使用的是注解方式,看了对应mapper的方法,注解都有了,没问题,关联了下源码,debug的时候发现,对应mapper中有部分方法是注册了的,而报错的方法没有被注册,怀疑是代码没编译,重新编译过后,问题还在,猜测可能是mybatis在注册的时候出错了,导致后续方法没有被注册。看了下源码,mybatis在Configuration类的getMapper方法中寻找statement,那肯定会有个地方在初始化的时候注册那些statement,在Configuration类中找到相似方法public <T> void addMapper(Class<T> type),追踪进去,这个方法调用了org.apache.ibatis.binding.MapperRegistry类的addMapper方法,代码如下:
public <T> void addMapper(Class<T> type) { if (type.isInterface()) { if (hasMapper(type)) { throw new BindingException("Type " + type + " is already known to the MapperRegistry."); } boolean loadCompleted = false; try { knownMappers.put(type, new MapperProxyFactory<T>(type)); // It's important that the type is added before the parser is run // otherwise the binding may automatically be attempted by the // mapper parser. If the type is already known, it won't try. MapperAnnotationBuilder parser = new MapperAnnotationBuilder(config, type); parser.parse(); loadCompleted = true; } finally { if (!loadCompleted) { knownMappers.remove(type); } } } }
追踪进入org.apache.ibatis.builder.annotation.MapperAnnotationBuilder类的parse方法
public void parse() { String resource = type.toString(); if (!configuration.isResourceLoaded(resource)) { loadXmlResource(); configuration.addLoadedResource(resource); assistant.setCurrentNamespace(type.getName()); parseCache(); parseCacheRef(); Method[] methods = type.getMethods(); for (Method method : methods) { try { parseStatement(method); } catch (IncompleteElementException e) { configuration.addIncompleteMethod(new MethodResolver(this, method)); } } } parsePendingMethods(); }
可以看到在这边获取了Mapper接口的所有方法,解析方法上的注解,继续追踪,进入parseStatement方法
void parseStatement(Method method) { Class<?> parameterTypeClass = getParameterType(method); LanguageDriver languageDriver = getLanguageDriver(method); SqlSource sqlSource = getSqlSourceFromAnnotations(method, parameterTypeClass, languageDriver); if (sqlSource != null) { Options options = method.getAnnotation(Options.class); final String mappedStatementId = type.getName() + "." + method.getName(); Integer fetchSize = null; Integer timeout = null; StatementType statementType = StatementType.PREPARED; ResultSetType resultSetType = ResultSetType.FORWARD_ONLY; SqlCommandType sqlCommandType = getSqlCommandType(method); boolean isSelect = sqlCommandType == SqlCommandType.SELECT; boolean flushCache = !isSelect; boolean useCache = isSelect; KeyGenerator keyGenerator; String keyProperty = "id"; String keyColumn = null; if (SqlCommandType.INSERT.equals(sqlCommandType)) { // first check for SelectKey annotation - that overrides everything else SelectKey selectKey = method.getAnnotation(SelectKey.class); if (selectKey != null) { keyGenerator = handleSelectKeyAnnotation(selectKey, mappedStatementId, getParameterType(method), languageDriver); keyProperty = selectKey.keyProperty(); } else { if (options == null) { keyGenerator = configuration.isUseGeneratedKeys() ? new Jdbc3KeyGenerator() : new NoKeyGenerator(); } else { keyGenerator = options.useGeneratedKeys() ? new Jdbc3KeyGenerator() : new NoKeyGenerator(); keyProperty = options.keyProperty(); keyColumn = options.keyColumn(); } } } else { keyGenerator = new NoKeyGenerator(); } if (options != null) { flushCache = options.flushCache(); useCache = options.useCache(); fetchSize = options.fetchSize() > -1 || options.fetchSize() == Integer.MIN_VALUE ? options.fetchSize() : null; //issue #348 timeout = options.timeout() > -1 ? options.timeout() : null; statementType = options.statementType(); resultSetType = options.resultSetType(); } String resultMapId = null; ResultMap resultMapAnnotation = method.getAnnotation(ResultMap.class); if (resultMapAnnotation != null) { resultMapId = resultMapAnnotation.value(); } else if (isSelect) { resultMapId = parseResultMap(method); } assistant.addMappedStatement( mappedStatementId, sqlSource, statementType, sqlCommandType, fetchSize, timeout, null, // ParameterMapID parameterTypeClass, resultMapId, // ResultMapID getReturnType(method), resultSetType, flushCache, useCache, false, // TODO issue #577 keyGenerator, keyProperty, keyColumn, null, languageDriver); } }
方法第三行,获取sqlSource,debug到这边的时候有出错(不是报 Invalid bound statement (not found)的犯法),去看了下报错的方法,原来报错的方法使用的是@UpdateProvider注解,但是属性type对应的类中没有method指定的方法,所以在执行代码
getSqlSourceFromAnnotations(method, parameterTypeClass, languageDriver);
时报了,但是项目启动的时候没错误日志,正常启动成功了,再看了下代码
private SqlSource getSqlSourceFromAnnotations(Method method, Class<?> parameterType, LanguageDriver languageDriver) { try { Class<? extends Annotation> sqlAnnotationType = getSqlAnnotationType(method); Class<? extends Annotation> sqlProviderAnnotationType = getSqlProviderAnnotationType(method); if (sqlAnnotationType != null) { if (sqlProviderAnnotationType != null) { throw new BindingException("You cannot supply both a static SQL and SqlProvider to method named " + method.getName()); } Annotation sqlAnnotation = method.getAnnotation(sqlAnnotationType); final String[] strings = (String[]) sqlAnnotation.getClass().getMethod("value").invoke(sqlAnnotation); return buildSqlSourceFromStrings(strings, parameterType, languageDriver); } else if (sqlProviderAnnotationType != null) { Annotation sqlProviderAnnotation = method.getAnnotation(sqlProviderAnnotationType); return new ProviderSqlSource(assistant.getConfiguration(), sqlProviderAnnotation); } return null; } catch (Exception e) { throw new BuilderException("Could not find value method on SQL annotation. Cause: " + e, e); } }
getSqlSourceFromAnnotations方法中会抛出BuilderException,而在之前的parse方法中捕获的是IncompleteElementException
for (Method method : methods) { try { parseStatement(method); } catch (IncompleteElementException e) { configuration.addIncompleteMethod(new MethodResolver(this, method)); } }
IncompleteElementException是BuilderException的子类,所以这边并不会被捕获,会继续往上抛,导致循环退出,mapper中的后续方法跳过注册,因此在代码执行的时候没有找到对应的statement。
唉,真是坑爹啊。
相关推荐
主要介绍了使用mybatis-plus报错Invalid bound statement (not found)错误,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
主要介绍了MybatisPlus BaseMapper 中的方法全部 Invalid bound statement (not found)的Error处理方法,本文给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下
主要介绍了MyBatis绑定错误提示BindingException:Invalid bound statement (not found)的解决办法,非常不错,具有参考借鉴价值,需要的的朋友参考下吧
主要介绍了引入mybatis-plus报 Invalid bound statement错误问题的解决方法,需要的朋友可以参考下
出现以上的情况主要的原因是因为在主配置文件标签没正确的指向映射接口的配置文件。 解决方案:1.检查的name是否正确,如我的name属性填的就是com.it.dao 2、检查的class属性或resource属性,我resource这里写的是...
本文通过实例代码给大家分享mybatis 引入映射器的方法,非常不错,具有参考借鉴价值,需要的朋友参考下吧
mybatis批量添加的时候报错总结报错 parameter'_frch_item_0 not found
NULL 博文链接:https://facekindle.iteye.com/blog/1613687
今天在项目中,使用Mybatis对oracle数据库进行操作的时候,报出ORA-00911: invalid character的错误,检查了一下SQL,发现都书写正确啊,复制到plsql上执行也都没问题,这什么原因呢,下面通过本文给大家解答下
目前IDEA的mybatis插件有两款,其中一款是收费的,这款是免费的,导入IDEA插件即可使用。
主要给大家介绍了mybatis中foreach报错:_frch_item_0 not found的解决方法,文章通过示例代码介绍了详细的解决方法,对大家具有一定的参考学习价值,需要的朋友们下面来一起看看吧。
mybatis入门案例mybatis入门案例mybatis入门案例mybatis入门案例mybatis入门案例mybatis入门案例mybatis入门案例mybatis入门案例mybatis入门案例mybatis入门案例mybatis入门案例mybatis入门案例mybatis入门案例...
mybatis源码是mybatis-3.2.6的源码,用户使用mybatis时可以进行参考
mybatis练习3mybatis练习3mybatis练习3mybatis练习3mybatis练习3mybatis练习3mybatis练习3mybatis练习3mybatis练习3mybatis练习3mybatis练习3mybatis练习3mybatis练习3mybatis练习3mybatis练习3mybatis练习3mybatis...
mybatis deom.mybatis 的简单入门实例。基于maven开发的。
包含mybatis-generator1.3.2的jar包、mysql数据库连接jar包、oracle数据库连接jar包、mybatis3.2.7.jar以及自动生成代码的配置文件模板。
开发工具 mybatis-3.4.2开发工具 mybatis-3.4.2开发工具 mybatis-3.4.2开发工具 mybatis-3.4.2开发工具 mybatis-3.4.2开发工具 mybatis-3.4.2开发工具 mybatis-3.4.2开发工具 mybatis-3.4.2开发工具 mybatis-3.4.2...
1、这是Eclipse MyBatis generator 1.3.7插件的核心包 2、首先到Eclipse中下载 MyBatis Generator 1.3.7插件,下载完按步骤进行安装 打开Help > Eclipse Marketplace > Search > 输入框输入 MyBatis Generator ...
mybatis、mybatis详细设计、mybatis配置
Plugin for Mybatis. Plugin was rewritten from scratch with new architecture to make it more stable and bringing many new features. The plugin provides the following features: Compatible with both IDEA...