See source solution: org.apache.ibatis.binding.BindingException: Parameter '0' not found

Keywords: Programming Mybatis Java Apache Spring

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);
  }

Posted by devil6600 on Sun, 08 Dec 2019 12:56:32 -0800