mybatis多个参数(不使用@param注解情况下),sql参数占位符正确写法


声明:本文转载自https://my.oschina.net/u/3737136/blog/1811654,转载目的在于传递更多信息,仅供学习交流之用。如有侵权行为,请联系我,我会及时删除。

useActualParamName配置

useActualParamName 允许使用方法签名中的名称作为语句参数名称。 为了使用该特性,你的工程必须采用Java 8编译,并且加上-parameters选项。(从3.4.1开始) true | false true

mybatis的全局配置useActualParamName决定了mapper中参数的写法,默认为true

代码展示:

@Test public void findUserById() {     SqlSession sqlSession = getSessionFactory().openSession();     UserDao userMapper = sqlSession.getMapper(UserDao.class);     User user = userMapper.findUserById(1,"lpf");     Assert.assertNotNull("没找到数据", user); }
public interface UserDao {     User findUserById (int id,String name); }

1.如果useActualParamName设置为true时

传递参数需要使用

#{arg0}-#{argn}或者#{param1}-#{paramn}

比如:

<select id="findUserById" resultType="com.lpf.entity.User" >   select * from m_user where id = #{arg0}  and name =#{arg1} </select>

或者

<select id="findUserById" resultType="com.lpf.entity.User" >   select * from m_user where id = #{param1}  and name =#{param2} </select>

2.如果useActualParamName设置为false时

传递参数需要使用

#{0}-#{n}或者#{param1}-#{paramn}

<select id="findUserById" resultType="com.lpf.entity.User" >   select * from m_user where id = #{0}  and name =#{1} </select>

或者

<select id="findUserById" resultType="com.lpf.entity.User" >   select * from m_user where id = #{param1}  and name =#{param2} </select>

下面是多个参数的错误写法直接写参数名(如果方法只有一个参数是可以用参数名代替的)

<select id="findUserById" resultType="com.lpf.entity.User" >   select * from m_user where id = #{id}  and name =#{name} </select>

源码解读(3.4.6):

在mapper的代理对象调用方法时,最终会是MapperMethod对象的execute方法。如下:

@Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {   try {     // 如果目标方法是Object类继承来的,直接调用目标方法     if (Object.class.equals(method.getDeclaringClass())) {       return method.invoke(this, args);     } else if (isDefaultMethod(method)) {       return invokeDefaultMethod(proxy, method, args);     }   } catch (Throwable t) {     throw ExceptionUtil.unwrapThrowable(t);   }   // 从缓存中获取MapperMethod 对象,如果没有就创建新的并添加   final MapperMethod mapperMethod = cachedMapperMethod(method);   // 执行sql 语句   return mapperMethod.execute(sqlSession, args); }

MapperMethod的一个内部类MethodSignature封装了Mapper接口中定义的方法的相关信息。而MethodSignature的一个属性ParamNameResolver对象处理接口中定义的方法的参数列表。

ParamNameResolver 的属性

// 记录参数在参数列表中的位置索引与参数名称之间的对应关系 private final SortedMap<Integer, String> names;  // 记录对应的方法参数是否使用了@Param注解 private boolean hasParamAnnotation;

ParamNameResolver的构造函数

/**  * 通过反射读取方法中的信息,并初始化上面两个字段  * @param config  * @param method  */ public ParamNameResolver(Configuration config, Method method) {   // 获取参数列表中每个参数的类型   final Class<?>[] paramTypes = method.getParameterTypes();   // 获取参数列表上的注解  @Param   final Annotation[][] paramAnnotations = method.getParameterAnnotations();   // 该集合用于记录参数索引与参数名称的对应关系   final SortedMap<Integer, String> map = new TreeMap<Integer, String>();   int paramCount = paramAnnotations.length;   // 遍历所有参数   for (int paramIndex = 0; paramIndex < paramCount; paramIndex++) {     if (isSpecialParameter(paramTypes[paramIndex])) {       // 如果参数是RowBounds类型或者ResultHandler类型,则跳过该参数       continue;     }     String name = null;     // 遍历该参数上的注解集合     for (Annotation annotation : paramAnnotations[paramIndex]) {       if (annotation instanceof Param) {         // 获取@Param注解指定的参数名称         hasParamAnnotation = true;         name = ((Param) annotation).value();         break;       }     }     // 没有@Param注解的话 执行下面逻辑     if (name == null) {       // useActualParamName==true时  即name = arg0 ...       if (config.isUseActualParamName()) {         name = getActualParamName(method, paramIndex);       }       if (name == null) {//useActualParamName == false是  即 name="0" ...         // use the parameter index as the name ("0", "1", ...)         // 使用参数的索引作为其名称         name = String.valueOf(map.size());       }     }     map.put(paramIndex, name);   }   names = Collections.unmodifiableSortedMap(map); }

names集合主要是在ParamNameResolver.getNamedParams方法中使用

/**  *  * @param args 用户参入的实参列表  * @return  */ public Object getNamedParams(Object[] args) {   final int paramCount = names.size();   if (args == null || paramCount == 0) {     return null;   } else if (!hasParamAnnotation && paramCount == 1) {// 未使用@Param注解且参数列表只有一个     return args[names.firstKey()];//即args[0]参数名称   } else {     // 下面是为参数创建param+索引的格式作为默认参数名称 如:param1  下标从1开始     final Map<String, Object> param = new ParamMap<Object>();     int i = 0;     for (Map.Entry<Integer, String> entry : names.entrySet()) {       param.put(entry.getValue(), args[entry.getKey()]);       // add generic param names (param1, param2, ...)       final String genericParamName = GENERIC_NAME_PREFIX + String.valueOf(i + 1);       // ensure not to overwrite parameter named with @Param       if (!names.containsValue(genericParamName)) {         param.put(genericParamName, args[entry.getKey()]);       }       i++;     }     return param;   } }

总结:

1.如果接口方法有一个或多个参数,并且使用了@Param注解,sql语句中的参数用注解的value值,

2.如果接口方法的参数只有一个,并且没有使用@Parma注解sql语句直接使用参数名称即可。

3.如果接口的方法有多个参数,并且没有使用@Parma注解,sql语句使用param1...paramn是不会错的。

 

本文发表于2018年05月14日 10:03
(c)注:本文转载自https://my.oschina.net/u/3737136/blog/1811654,转载目的在于传递更多信息,并不代表本网赞同其观点和对其真实性负责。如有侵权行为,请联系我们,我们会及时删除.

阅读 3582 讨论 0 喜欢 1

抢先体验

扫码体验
趣味小程序
文字表情生成器

闪念胶囊

你要过得好哇,这样我才能恨你啊,你要是过得不好,我都不知道该恨你还是拥抱你啊。

直抵黄龙府,与诸君痛饮尔。

那时陪伴我的人啊,你们如今在何方。

不出意外的话,我们再也不会见了,祝你前程似锦。

这世界真好,吃野东西也要留出这条命来看看

快捷链接
网站地图
提交友链
Copyright © 2016 - 2021 Cion.
All Rights Reserved.
京ICP备2021004668号-1