Wrong information
org.mybatis.spring.MyBatisSystemException: nested exception is org.apache.ibatis.binding.BindingException: Parameter '0' not found. Available parameters are [arg1, arg0, param1, param2] at org.mybatis.spring.MyBatisExceptionTranslator.translateExceptionIfPossible(MyBatisExceptionTranslator.java:77) at org.mybatis.spring.SqlSessionTemplate$SqlSessionInterceptor.invoke(SqlSessionTemplate.java:446) at com.sun.proxy.$Proxy98.selectList(Unknown Source) at org.mybatis.spring.SqlSessionTemplate.selectList(SqlSessionTemplate.java:230) at org.apache.ibatis.binding.MapperMethod.executeForMany(MapperMethod.java:137) at org.apache.ibatis.binding.MapperMethod.execute(MapperMethod.java:75) at org.apache.ibatis.binding.MapperProxy.invoke(MapperProxy.java:59) at com.sun.proxy.$Proxy144.getProcessNodeList(Unknown Source)
Cause analysis
1. In the Mapper class of Mybatis, @ Param("xxx") is not added as the parameter description before the parameter; 2. The version of Mybatis has been upgraded to the version after 3.4.2;
Solution
1. Add the following in application.properties (or bootstrap.yml, or configuration center, etc.):
mybatis.configuration.use-actual-param-name=false
2. Restart the application
Source code analysis
- The interface parameters in mapper.java are defined as follows:
UserModel findById(Integer id);
- The sql statements in mapper.xml are used as follows
<select id="findById" resultType="com.gongstring.model.UserModel"> SELECT user_id userId,user_name userName FROM demo_user WHERE user_id=#{0} ORDER BY time_created DESC LIMIT 1 </select>
Key point: the {0} used in parameter acquisition
- In the org.apache.ibatis.session.Configuration class
protected boolean useActualParamName = true;
According to the source code log, in the submission record on May 17, 2016, the parameter was changed from the original false to true. It is speculated that we want to reduce the direct use of {0}, {1} and other query conditions in the subsequent version, and we recommend the use of {param1}, {param2} prefix, of course, it is better to write @ param annotation to declare the variable name. For submission log, see: https://github.com/mybatis/mybatis-3/commit/3f19d04b6ef2a09c452c104d8eb680b37b246b0a#diff-65ade3ef0e889aa04b75e6bb408e3787
- org.apache.ibatis.reflection.ParamNameResolver
When the Mybatis service is started, it initializes the ParamNameResolver name conversion object. There are rules about the definition of name variables:
public ParamNameResolver(Configuration config, Method method) { final Class<?>[] paramTypes = method.getParameterTypes(); final Annotation[][] paramAnnotations = method.getParameterAnnotations(); final SortedMap<Integer, String> map = new TreeMap<Integer, String>(); int paramCount = paramAnnotations.length; // get names from @Param annotations for (int paramIndex = 0; paramIndex < paramCount; paramIndex++) { if (isSpecialParameter(paramTypes[paramIndex])) { // skip special parameters continue; } String name = null; for (Annotation annotation : paramAnnotations[paramIndex]) { if (annotation instanceof Param) { hasParamAnnotation = true; name = ((Param) annotation).value(); break; } } if (name == null) { // @Param was not specified if (config.isUseActualParamName()) { //If @ Param annotation is available, the parameter value is set with annotation name first name = getActualParamName(method, paramIndex); } if (name == null) { // use the parameter index as the name ("0", "1", ...) // gcode issue #71 name = String.valueOf(map.size()); } } map.put(paramIndex, name); } names = Collections.unmodifiableSortedMap(map); }