首页 > 其他分享 >技术框架中MyBatis参数传递的学习

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

时间:2024-12-04 20:32:21浏览次数:2  
标签:name 框架 age 接口 参数传递 参数 user MyBatis id

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("参数名") 为参数取别名(可读性高)
  • 建议只要能用 #{ } 的地方尽量不使用 ${ }(安全性高)

标签:name,框架,age,接口,参数传递,参数,user,MyBatis,id
From: https://www.cnblogs.com/BingBing-8888/p/18587117

相关文章

  • 参数传递进阶*args和**kwargs
    '''函数的参数传递进阶:在python中,所有的函数,在传入参数的时候,参数都会变成*args和**kwargs两种形态1.*args表示以元组的形态*表示参数基于元组的形态进行接受和解析。根本意义上就是拆包。将元组中的元素拆包成不同的数据,转为参数传入*......
  • flask框架大学生社团管理系统毕设源码+论文
    本系统(程序+源码+数据库+调试部署+开发环境)带论文文档1万字以上,文末可获取,系统界面在最后面。系统程序文件列表开题报告内容一、选题背景关于大学生社团管理系统的研究,现有研究主要以社团基本管理功能为主,如成员管理、活动管理等,专门针对社团内部细致的部门结构相关功能,像......
  • flask框架宠物领养系统毕设源码+论文
    本系统(程序+源码+数据库+调试部署+开发环境)带论文文档1万字以上,文末可获取,系统界面在最后面。系统程序文件列表开题报告内容一、选题背景关于宠物领养相关系统的研究,现有研究主要以宠物交易系统或者单纯的宠物信息展示平台为主,专门针对宠物领养系统全方位功能(如包含用户、......
  • SpringBoot连接多数据源MySQL、SqlServer等(MyBatisPlus测试)
    SpringBoot连接多数据源MySQL、SqlServer等(MyBatisPlus测试)在实际的项目开发中,我们往往需要同时连接多个数据源对数据进行处理。本文将详细介绍在SpringBoot下配合MybatisPlus如何连接多数据源,实例将会使用连接MySQL、SqlServer进行测试,可自行根据思路供自行连接Oracle、Po......
  • ssm框架整合
    BookController类packagecom.hkd.controller;importcom.hkd.pojo.Book;importcom.hkd.service.BookService;importorg.springframework.beans.factory.annotation.Autowired;importorg.springframework.stereotype.Controller;importorg.springframework.web.bind.......
  • uniapp精仿微信源码,基于SumerUI和Uniapp前端框架的一款仿微信APP应用,界面漂亮颜值高,视
    uniapp精仿微信源码,基于SumerUI和Uniapp前端框架的一款仿微信APP应用,界面漂亮颜值高,视频商城小工具等,朋友圈视频号即时聊天用于视频,商城,直播,聊天,等等场景,源码分享sumer-weixin介绍uniapp精仿微信,基于SumerUI3.0和Uniapp前端框架的一款仿微信APP应用,界面漂亮颜值高,视频......
  • 阿里:LLM自我拓展的迭代训练框架
    ......
  • mybatis集成篇(二)--Springboot集成mybatis
    前言随着Spring框架越来越成熟,推出的Springboot使用也越来越广,Mybatis随其自然地适配Springboot。Springboot集成Mybatis使用application.yml配置mybatis:mapper-locations:classpath:./mapper/*Mapper.xmlconfiguration:map-underscore-to-camel-case:tru......
  • flask框架电竞赛事管理系统毕设源码+论文
    本系统(程序+源码+数据库+调试部署+开发环境)带论文文档1万字以上,文末可获取,系统界面在最后面。系统程序文件列表开题报告内容一、选题背景关于电竞赛事管理系统的研究,现有研究多集中在电竞产业的宏观发展、个别赛事的组织流程等方面,专门针对一个综合且全面的电竞赛事管理系......
  • flask框架党支部建设管理平台毕设源码+论文
    本系统(程序+源码+数据库+调试部署+开发环境)带论文文档1万字以上,文末可获取,系统界面在最后面。系统程序文件列表开题报告内容一、选题背景关于党支部建设管理的研究,现有研究主要以传统的党建工作模式及理论探讨为主。在信息化飞速发展的今天,虽然有部分地区开始探索党建信息......