技术框架中MyBatis参数传递的学习

MyBatis参数传递总结

MyBatis参数传递#{}方式

情况一:Mapper 映射器接口方法参数只有一个且为基本类型

接口方法:

public List<UserEntity> selectUserByAge(int age);

映射结果:

<select id="selectUserByAge" resultMap="userResultMap">select * from tb_user where age > #{age};
</select>

其中 #{参数名} 表示参数占位符,等价于SQL语句的 号,这里的 #{age} 对应的就是接口方法 selectUserByAge 的参数。由于只有一个参数,而且是基本类型,所以写成 #{userAge} 或者 #{ageUser} 都无所谓,反正作用是一样的。

情况二:Mapper映射器接口方法参数有两个基本类型

接口方法:

public int updateUser(int id, String name);

映射结果:

<update id="updateUser">update tb_user set name=#{name} where id=#{id};
</update>

接口方法 updateUser 有两个参数且都是基本类型,按理说直接使用 #{参数名} 就可以了,不过一运行居然报错,如下:

### SQL: update tb_user set name=? where id=?;
### Cause: org.apache.ibatis.binding.BindingException: Parameter 'name' not found. Available parameters are [0, 1, param1, param2]

从错误信息描述看,说是参数 name 没有发现,有效的参数是 [arg0, arg1, param1, param2]。这是什么意思呀? 意思就是说当遇到不只一个参数时,比如两个参数,就不能用 #{参数名} 作为占位符,可以用 MyBatis 提供了两种方式之一。

  • 方式一#{arg0} 表示第一个参数 name,#{arg1} 表示第二个参数 id,#{arg2} 表示第三个参数...

    使用如下:

    <update id="updateUser">update tb_user set name=#{arg0} where id=#{arg1};
    </update>
  • 方式二#{param1} 表示第一个参数 name,#{param2} 表示第二个参数 id,#{param3} 表示第三个参数...

    使用如下:

<update id="updateUser">update tb_user set name=#{param1} where id=#{param2};
</update>

其实,如果你非要用 #{参数名} 作为占位符,还可以用 MyBatis 提供的第三种方式,如下:

  • 方式三:给接口方法的参数取别名,只要参数别名和 #{参数名} 相同就可以了。

    使用如下:

// @Param("id")表示给参数 int id 取别名为id,@Param("name") 表示给参数 name 取别名为name
public int updateUser(@Param("id") int id,@Param("name") String name);
<update id="updateUser">update tb_user set name=#{name} where id=#{id};
</update>

sql 中使用 arg0,arg1,arg..param1、param2、param... 这种方式来引用多参数,对参数的顺序依赖性特别强,如果有人把参数的顺序调整了或者调整了参数的个数,后果就是灾难性的,所以这两种方式不建议大家使用。

推荐大家使用第三种方式,不仅可读性高,而且参数顺序可以任意调整。

情况三:Mapper 映射器接口方法参数为 Map 类型

接口方法:

public List<UserEntity> selectByMap(Map<String,Object> map);

映射结果:

<select id="selectByMap" resultType="entity.UserEntity"><![CDATA[SELECT * FROM tb_user WHERE age=#{age} OR sex = #{sex}]]>
</select>
情况四:Mapper 映射器接口方法参数只有一个且为引用类型

接口方法:

public int insertUser(UserEntity user);

映射结果:

<insert id="insertUser">insert into tb_user (id,userName, password, name, age, sex, birthday, created, updated) values(null,#{userName},#{password},#{name},#{age},#{sex},#{birthday},now(),now());
</insert>

接口方法 insertUser 的参数是引用类型,其实传递给 SQL 语句的参数是引用类型的属性值,SQL 语句本身是不支持引用类型的。那引用类型有很多属性(或成员变量),是如何与 SQL 语句的参数一一对应的呢?

答案是使用 #{引用类型的属性名} ,这里需要注意的是属性名不能写错了,否则就无法与 SQL 语句的参数对应,无法正确传递参数哈。

public class UserEntity {private int id;private String userName;private String password;private String name;private int age;private int sex;private Date birthday;private String created;private String updated;
}

由于是自增主键,所以不需要传递引用类型的 id 参数,使用 null 代替,数据库会自动生成主键 id 标识。

传递 java 对象的方式相对于 map 的方式更清晰一些,可以明确知道具体有哪些参数,而传递 map,我们是不知道这个 map 中具体需要哪些参数的,map 对参数也没有约束,参数可以随意传,建议多个参数的情况下选择通过 java 对象进行传参

情况五:Mapper 映射器接口方法参数有两个引用类型

接口方法:

public List<UserEntity> selectUserByAgeAndSex(@Param("userOne") UserEntity userOne,@Param("userTwo") UserEntity userTwo);

映射结果1:

<select id="selectUserByAgeAndSex" resultMap="userResultMap">select * from tb_user where age > #{userOne.age} and sex = #{userTwo.sex};
</select>

映射结果2:

<select id="selectUserByAgeAndSex" resultMap="userResultMap">select * from tb_user where age > #{param1.age} and sex = #{param2.sex};
</select>

以上两种映射方式都可以,但是如果没有为两个参数取 @Param("userOne") 和 @Param("userTwo") 别名的话,那么就只有映射结果2可以了,映射结果1将会报错。

爱思考的你可能会问,MyBatis 不是还有一种传参的方式吗?如下映射方式是否可以?

<select id="selectUserByAgeAndSex" resultMap="userResultMap">select * from tb_user where age > #{arg0.age} and sex = #{arg1.sex};
</select>

回答这个问题很简单,试一试不就知道了嘛。测试结果如下:

### Error querying database.  Cause: org.apache.ibatis.binding.BindingException: Parameter '0' not found. Available parameters are [userOne, userTwo, param1, param2]
### Cause: org.apache.ibatis.binding.BindingException: Parameter '0' not found. Available parameters are [userOne, userTwo, param1, param2]

测试结果报错,这说明#{arg0}、#{arg1}这种参数占位符的方式只适用于参数是基本类型,不适用于参数是引用类型。

情况六:Mapper 映射器接口方法参数有多个(包括基本类型和引用类型)

接口方法:

public List<UserEntity> selectUserByNameAndAge(@Param("name") String name, @Param("user") UserEntity user);

映射结果1:

<select id="selectUserByNameAndAge" resultMap="userResultMap">select * from tb_user where name = #{name} and age > #{user.age};
</select>

映射结果2:

<select id="selectUserByNameAndAge" resultMap="userResultMap">select * from tb_user where name = #{param1} and age > #{param2.age};
</select>

以上两种映射方式都可以。

看到这里,相信你应该对 MyBatis 的#{ }传参方式已经胸有成竹了吧。无论接口方法的参数个数如何、类型如何,你应该都知道如何映射。

情况七:Mapp 映射器接口方法参数为 Collection 类型

当传递的参数类型是Collection的时候,会被放在 map 中,key为collection,value 为参数的值

接口方法:

public List<UserEntity> selectByCollection(Collection<Integer> ages);

映射结果:

<select id="selectByCollection" resultType="entity.UserEntity"><![CDATA[SELECT * FROM tb_user WHERE age in (#{list[0]},#{list[1]})]]>
</select>
Mybatis 中集合参数处理了源码解析

集合参数,mybatis会进行一些特殊处理,代码在下面的方法中:

org.apache.ibatis.session.defaults.DefaultSqlSession#wrapCollection

源码解释:

判断参数是否是java.util.Collection类型,如果是,会放在map中,key为collection。如果参数是java.util.List类型的,会在map中继续放一个list作为key来引用这个对象。如果参数是数组类型的,会通过array来引用这个对象。

情况八:Mapper 映射器接口方法参数为 ResultHandler 类型

查询的数量比较大的时候,返回一个 List 集合占用的内存还是比较多的,比如我们想导出很多数据,实际上如果我们通过jdbc的方式,遍历ResultSetnext方法,一条条处理,而不用将其存到 List 集合中再取处理。

mybatis中也支持我们这么做,可以使用ResultHandler对象,犹如其名,这个接口是用来处理结果的,先看一下其定义:

public interface ResultHandler<T> {void handleResult(ResultContext<? extends T> resultContext);
}

里面有1个方法,方法的参数是ResultContext类型的,这个也是一个接口,看一下源码:

public interface ResultContext<T> {T getResultObject();int getResultCount();boolean isStopped();void stop();
}

4 个 方法:

  • getResultObject:获取当前行的结果
  • getResultCount:获取当前结果到第几行了
  • isStopped:判断是否需要停止遍历结果集
  • stop:停止遍历结果集

ResultContext接口有一个实现类org.apache.ibatis.executor.result.DefaultResultContext,mybatis中默认会使用这个类。

遍历tb_user表的所有记录,第 2 条遍历结束之后,停止遍历

接口方法:

void getList(ResultHandler<UserEntity> resultHandler);

映射结果:

<select id="getList" resultType="entity.UserEntity"><![CDATA[SELECT * FROM tb_user]]>
</select>

测试代码:

@Test
public void getListTest() {userMapper.getList(context->{//将context参数转换为DefaultResultContext对象DefaultResultContext<UserEntity> defaultResultContext= (DefaultResultContext<UserEntity>) context;//打印遍历结果System.out.println(defaultResultContext.getResultObject());//遍历到第二条之后停止if (defaultResultContext.getResultCount() == 2) {//调用stop方法停止遍历,stop方法会更新内部的一个标志,置为停止遍历defaultResultContext.stop();}});
}

MyBatis 参数传递 #{} 和 ${} 区别

原理
  • { }:为参数占位符?(即底层使用了 JDBC 的 PreparedStatement 来进行预处理)

  • ${ }:为字符串替换(即底层使用了 JDBC 的 Statement 直接进行查询)
参数传递
  • { }: 传递参数后 SQL 语句自动为参数加上单引号

  • ${ }: 传递参数后 SQL 语句不会为参数加上单引号
SQL 注入
  • { }:可以防止 sql 注入

  • ${ }:不可以防止 sql 注入

注:SQL 注入是黑客攻击服务器的一种简单手段,感兴趣的话可以去看我写的关于 SQL 注入的详细博客文章。

MyBatis 参数传递总结

参数传递方式

  • 参数传递 #{ } 方式:#{arg0} 、 #{param1} 、 @param(别名) / #
  • 参数传递 ${ } 方式:用法同 #{ } 相同,注意与 #{ } 的区别
项目开发建议
  • 建议接口参数一律使用 @param("参数名") 为参数取别名(可读性高)
  • 建议只要能用 #{ } 的地方尽量不使用 ${ }(安全性高)

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

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

相关文章

电感的通低频阻高频特性的测试

用手持电桥测出电感的实际值,以保证在这个频率附近电感数值不会有太大变化 10k档     40k档   100k档 9.96mH    9.77mH   17.25mH 用示波器的信号发生器产生一个200k的信号,串接以上电感,查看输出波形当信号为200k时输出波形的峰峰值为1.55V(不接电感时为2.44…

荡秋

我怎么会写这种东西?共享单车框里载着最后一片黄黄的秋 心想要不将它保住 过减速带,咯噔 秋荡出去了 摇摇晃晃地挣扎了好一会儿 还是落了地 还好我坐稳了,手机也没掉 安全回到宿舍

参数传递进阶*args和**kwargs

函数的参数传递进阶:在python中,所有的函数,在传入参数的时候,参数都会变成*args和**kwargs两种形态1.*args表示以元组的形态*表示参数基于元组的形态进行接受和解析。根本意义上就是拆包。将元组中的元素拆包成不同的数据,转为参数传入*可以接收无限长度的参数。因为所有…

return和global关键字

return关键字:1.函数默认没有返回值2.函数执行return之后,会停止运行3.函数是否有return结果,与print无关系,能够在控制台打印,不代表就有返回值。我们只看是否有return关键字 # def demo(a): # return a+10 # # def demo_no(): # pass # # print(demo(90)) #…

whk1

选 \(B\)。

0/1地图问题

打开所有的灯 题目描述 这个灯很奇怪,点一下就会将这个灯和其周围四盏灯的开关状态全部改变。现在你的任务就是就是告诉pmshz要全部打开这些灯。 例如 0 1 1 1 0 0 1 0 1点一下最中间的灯【2,2】就变成了 0 0 1 0 1 1 1 1 1再点一下左上角的灯【1,1】就变成了 1 …

测试的基本内容

1、谈谈你对测试理解? 测试是对软件的正确性进行验证,寻找可能存在的缺陷 2、测试从哪些角度考虑? 需求测试,界面测试,功能测试,可靠性测试,可移植性测试, 兼容性测试,安全性测试,性能测试,易操作性测试 3、公司中包含哪些人员? 开发主管,测试主管,开发人员,测试…

islide 插件安装之后能在office PPT里面显示,但是没法在WPS里面显示...好奇怪

在COM加载项里面也找不到slide... 真的是 先放一放 希望时间能让它自己解决(乐) https://www.islide.cc/help/article/302