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

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

useActualParamName配置

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

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();// 获取参数列表上的注解  @Paramfinal 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 @Paramif (!names.containsValue(genericParamName)) {param.put(genericParamName, args[entry.getKey()]);}i++;}return param;}
}

总结:

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

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

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

4.sql语句中的参数占位符名称和接口方法的参数名称没有什么关系。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/322745.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

如何封装并发布一个属于自己的ui组件库

以前就一直有个想法自己能不能封装一个类似于elementui一样的组件库&#xff0c;然后发布到npm上去&#xff0c;毕竟前端说白了&#xff0c;将组件v上去&#xff0c;然后进行数据交互。借助这次端午&#xff0c;终于有机会&#xff0c;尝试自己去封装发布组件库了 我这里了只做…

P1768-天路【负环,SPFA,01分数规划,二分答案】

正题 题目链接:https://www.luogu.org/problemnew/show/P1768 题目大意 求一条回路使得路上∑vi∑pi\frac{\sum v_i}{\sum p_i}∑pi​∑vi​​最大。 解题思路 考虑01分数规划 ∑vi∑pians\frac{\sum v_i}{\sum p_i}ans∑pi​∑vi​​ans ∑vians∗∑pi\sum v_ians*\sum p_i…

听云支持.NET Core的应用性能监控

随着微软于2017年8月正式发布.NET Core 2.0&#xff0c; .NET Core 社区开始活跃&#xff0c;众多.NET开发者开始向跨平台转变。 听云于2017年11月推出了.NET Core应用监控工具&#xff0c;和听云其他语言的监控工具一样&#xff0c;.NET Core应用监控工具具有以下特征&#xf…

mybatis源码阅读(五) ---执行器Executor

转载自 mybatis源码阅读(五) ---执行器Executor 1. Executor接口设计与类结构图 public interface Executor {ResultHandler NO_RESULT_HANDLER null;// 执行update&#xff0c;delete&#xff0c;insert三种类型的sql语句int update(MappedStatement ms, Object parameter…

.sync的一个用法

面试时&#xff0c;有人问了我修饰符是什么&#xff0c;就是一个点后面加一个单词&#xff0c;我当时还以为是什么文件夹后缀呢。很是尴尬 这里主要学习下.sync的一个用法 假设下场景&#xff1a; 这里有一个父组件&#xff0c;父组件中有个money&#xff0c;需要传到子组件中…

nssl1296-猫咪的进化【dp】

正题 题目大意 nnn次&#xff0c;每次有3种选择&#xff1a; 休息获得viv_ivi​点价值获得vi2v_i^2vi2​点价值且下一回合要休息 解题思路 定义fi,0/1/2f_{i,0/1/2}fi,0/1/2​表示第iii次为休息/叫一声/叫两声时的最大价值。 fi,0f_{i,0}fi,0​可以由前面任何状态转移过来。 …

[52ABP实战系列] .NET CORE实战入门第三章更新了

早安 各位道友好&#xff0c;.NET CORE入门视频的第三章也算录制完毕了。欢迎大家上传课网进行学习。 更新速度 大家也知道最近的社会新闻比较多。频繁发生404、关键字打不出来&#xff0c;我个人也在关注这些事件。导致精力分散&#xff0c;没有做到稳定更新&#xff0c;现在呢…

如何安装nuxt

因为vue是单页面应用&#xff0c;所以不被Seo&#xff0c;如百度和Google抓取到&#xff0c;在Vue中如果想要爬虫爬到就必须使用nuxt 那么如何安装使用呢&#xff1f; yarn create nuxt-app <project-name> cd <project-name> yarn build yarn start必须先build&a…

mybatis源码阅读(六) ---StatementHandler了解一下

转载自 mybatis源码阅读(六) ---StatementHandler了解一下 StatementHandler类结构图与接口设计 BaseStatementHandler&#xff1a;一个抽象类&#xff0c;只是实现了一些不涉及具体操作的方法 RoutingStatementHandler&#xff1a;类似路由器&#xff0c;根据配置文件来路由…

nssl1298-网站计划【线段树】

正题 题目大意 若干个区间操作l,rl,rl,r 让答案增加(lr)∗max{ai}(i∈[l..r])(lr)*max\{a_i\}(i\in[l..r])(lr)∗max{ai​}(i∈[l..r]) 并把最大的数变为0 解题思路 线段树&#xff0c;上传最大值时多上传一个位置&#xff0c;然后单点修改。 codecodecode #include<cstd…

输入框限定保留三位小数点

这里用到正则表达式&#xff0c;没输入一个数字会对输入框进行一次事件的触发&#xff0c;检查是否超过三位小数点&#xff0c;超过则进行删除。 你可以3改成2&#xff0c;这样就是保留两位小数点了 <el-input placeholder"请输入商品重量" v-model"baseInfo…

基于OIDC(OpenID Connect)的SSO(纯JS客户端)

在上一篇基于OIDC的SSO的中涉及到了4个Web站点&#xff1a; oidc-server.dev&#xff1a;利用oidc实现的统一认证和授权中心&#xff0c;SSO站点。 oidc-client-hybrid.dev&#xff1a;oidc的一个客户端&#xff0c;采用hybrid模式。 oidc-client-implicit.dev&#xff1a;od…

mybatis源码阅读(七) ---ResultSetHandler了解一下

转载自 mybatis源码阅读(七) ---ResultSetHandler了解一下 1、MetaObject MetaObject用于反射创建对象、反射从对象中获取属性值、反射给对象设置属性值&#xff0c;参数设置和结果封装&#xff0c;用的都是这个MetaObject提供的功能。 public static MetaObject forObject…

nssl1299-选做作业【最大流,最小割,最大子权闭合图】

正题 题目大意 有nnn个任务&#xff0c;完成需要先决条件&#xff0c;然后有完成价值。选择一些任务完成&#xff0c;求最大价值。 解题思路 首先&#xff0c;如果有环&#xff0c;那么这些环是不可能完成的。所以先用拓扑排序找环。 然后考虑最大子权闭合图&#xff0c;对于…

IIS中的 Asp.Net Core 和 dotnet watch

在基于传统的.NET Framework的Asp.Net Mvc的时候&#xff0c;本地开发环境中可以在IIS中建立一个站点&#xff0c;可以直接把站点的目录指向asp.net mvc的项目的根目录。然后build一下就可以在浏览器里面刷新到最新的修改了&#xff0c;也可以附加到w3wp的进程进行调试。但是在…

mybatis源码阅读(八) ---Interceptor了解一下

转载自 mybatis源码阅读(八) ---Interceptor了解一下 1 Intercetor MyBatis 允许你在已映射语句执行过程中的某一点进行拦截调用。默认情况下&#xff0c;MyBatis允许使用插件来拦截的方法调用包括&#xff1a; Executor (update, query, flushStatements, commit, rollba…

foreach方法使用

用法 foreach方法主要是针对数组而言的&#xff0c;对数组中的每个元素可以执行一次方法 var array [a, b, c, e]; array.forEach((a)> {console.log(a); });属性 foreach方法主要有三个参数&#xff0c;分别是数组内容、数组索引、整个数组 var array [a, b, c, e]; arra…

ssl提高组周六模拟赛【2019.3.2】

前言 Rank1Rank1Rank1耶 成绩 RankRankRank是有算别人的 只放前Rank10Rank10Rank10 RankRankRankPersonPersonPersonScoreScoreScoreAAABBBCCCDDD111meselfmeselfmeself340340340808080100100100100100100606060222XXYXXYXXY250250250808080707070100100100000333LWLWLW2502502…

.NET Core 控制台程序读 appsettings.json 、注依赖、配日志、设 IOptions

.NET Core 控制台程序没有 ASP.NET Core 的 IWebHostBuilder 与 Startup.cs &#xff0c;那要读 appsettings.json、注依赖、配日志、设 IOptions 该怎么办呢&#xff1f;因为这些操作与 ASP.NET Core 无依赖&#xff0c;所以可以自己动手&#xff0c;轻松搞定。 1、读 appsett…

Object.keys方法拿到对象的key值

项目中的高级搜索选项用到了Object.keys方法&#xff0c; 那么它是用来干嘛的呢&#xff1a;删除某个子对象里的数据 var anObj { aaa: kejin,bbb: shenxian,ccc: yuanshan };let params {...anObj,ddd: luanwu } console.log(params) console.log(Object.keys(anObj)); // …