MyBatis动态推理参数类型

news/2025/3/14 16:45:24/

前言

思考一个问题,前面的#{}和${}的区别中,我们知道了#{},MyBatis底层调用的是preparestatement这种预编译的方式,这种方式sql语句会预先编程 select * from t_user where id = ?这种形式,随后调用setInt(),setString(),…等方法为?赋值,但是myBatis是怎样知道参数是什么类型呢?这个就是MyBatis的动态推理了。具体是怎样推理的我们不再讨论,接下来我们讨论有哪些数据类型,MyBatis可以动态推理出来。

接下来通过各种查询来测试

准备工作
在这里插入图片描述
在这里插入图片描述

简单数据类型且只有一个参数

String

接口中方法

/**** 通过姓名来查询* @param id* @return*/List<Student> selectById(Long id);

Sql映射文件中代码(完整写法,告诉MyBatis我们的参数是什么类型的)

<select id="selectByName" resultType="Student" parameterType="java.lang.String">select * from t_student where name = #{name}</select>

测试代码

@Testpublic void testSelectByName(){SqlSession sqlSession = SqlSessionUtil.openSession();StudentMapper mapper = sqlSession.getMapper(StudentMapper.class);List<Student> students = mapper.selectByName("张三");for (Student s : students){System.out.println(s);}sqlSession.close();}

测试结果
在这里插入图片描述
可以看出可以正常的查出来

缺省一下parameterType

 <select id="selectByName" resultType="Student">select * from t_student where name = #{name}</select>

再次运行结果
在这里插入图片描述
可以看出MyBatis可以正确地推导出参数类型

java.util.Date

接口中方法

/**** 根据birth查询* @param birth* @return*/List<Student> selectByBirth(Date birth);

sql语句映射文件中代码(缺省版)

<select id="selectByBirth" resultType="Student">select * from t_student where birth = #{birth}</select>

测试代码

@Testpublic void testSelectByBirth() throws ParseException {SqlSession sqlSession = SqlSessionUtil.openSession();StudentMapper mapper = sqlSession.getMapper(StudentMapper.class);SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");Date birth = sdf.parse("1998-02-12");List<Student> students = mapper.selectByBirth(birth);for (Student s : students){System.out.println(s);}sqlSession.close();}

测试结果
在这里插入图片描述
可以看出,Date类型也可以缺省

具体都有哪些简单数据类型可以缺省呢?

经测试以下类型都可以缺省
byte short int long float double char
Byte Short Integer Long Float Double Character
String
java.util.Date
就不一一测试了

Map参数

接口中代码

 /**** 根据姓名和年龄来查询* @param map* @return*/List<Student> selectByNameAndAge(Map<String, Object> map);

Sql映射文件中代码(缺省版本)

<select id="selectByNameAndAge" resultType="Student">select * from t_student where name = #{sname} and age = #{sage}</select>

注意#{}中的值必须是map中的键值
测试代码

@Testpublic void testSelectByNameAndAge(){SqlSession sqlSession = SqlSessionUtil.openSession();StudentMapper mapper = sqlSession.getMapper(StudentMapper.class);Map<String, Object> map = new HashMap<>();map.put("sname","张三");map.put("sage",20);List<Student> students = mapper.selectByNameAndAge(map);for(Student s : students)System.out.println(s);sqlSession.close();}

运行结果
在这里插入图片描述
得出结论Map也可以缺省

实体类参数

接口中代码

/**** 保存学生信息* @param s* @return*/int insert(Student s);

Sql映射文件中代码(缺省parameterType)

<insert id="insert">insert into t_student values(null,#{name},#{age},#{height},#{birth},#{sex})</insert>

测试代码

@Testpublic void testInsert(){SqlSession sqlSession = SqlSessionUtil.openSession();StudentMapper mapper = sqlSession.getMapper(StudentMapper.class);Student student = new Student(null, "赵六", 18, 1.7, new Date(), '男');int count = mapper.insert(student);System.out.println(count);sqlSession.commit();sqlSession.close();}

运行结果
在这里插入图片描述
在这里插入图片描述
可以看出参数是实体类的时候也是可以缺省的

多个参数的情况

接口中代码

/**** 通过姓名和性别来进行查询* @param name* @param sex* @return*/List<Student> selectByNameAndSex(String name,Character sex);

Sql映射文件中代码(缺省参数类型)

 <select id="selectByNameAndSex" resultType="Student">select * from t_student where name = #{name} and sex = #{sex}</select>

测试代码

@Testpublic void testSelectByNameAndSex(){SqlSession sqlSession = SqlSessionUtil.openSession();StudentMapper mapper = sqlSession.getMapper(StudentMapper.class);List<Student> students = mapper.selectByNameAndSex("张三", '男');for(Student s : students)System.out.println(s);sqlSession.close();}

测试结果
在这里插入图片描述

可以看出运行出现了问题,提醒参数name没有找到,并且提醒可用的参数为[arg1, arg0, param1, param2]
更改Sql映射文件中的代码为如下

<select id="selectByNameAndSex" resultType="Student">select * from t_student where name = #{arg0} and sex = #{arg1}</select>

再次运行结果为
在这里插入图片描述
将文件更改为

<select id="selectByNameAndSex" resultType="Student">select * from t_student where name = #{param1} and sex = #{param2}</select>

也可以通过

结论

可以看出当参数有多个的时候,MyBatis已经为我们起好了参数名,我们需要正确地使用MyBatis为我们准备好的参数名

arg0 是第⼀个参数

param1是第⼀个参数

arg1 是第⼆个参数

param2是第⼆个参数

实现原理:实际上在mybatis底层会创建⼀个map集合,以arg0/param1为key,以⽅法上的参数为 value
例如如下代码

Map<String,Object> map = new HashMap<>();
map.put("arg0", name);
map.put("arg1", sex);
map.put("param1", name);
map.put("param2", sex);
// 所以可以这样取值:#{arg0} #{arg1} #{param1} #{param2}
// 其本质就是#{map集合的key}

注意:使⽤mybatis3.4.2之前的版本时:要⽤#{0}和#{1}这种形式。

疑问:我们必须使用MyBatis为我们准备的参数吗? @Param注解登场


@Param注解(命名参数)

如果我们不想使用系统提供的参数名,我们可以自己规定吗?答案是肯定的

我们可以使用@Param来为参数起名字(也就是底层Map中参数对应的key值名)

实战

接口中的代码

/**** 通过姓名和性别来进行查询* @param name* @param sex* @return*/List<Student> selectByNameAndSex(@Param(value = "name") String name,@Param("sex") Character sex);

value = 可以省略

更改Sql映射文件中的代码

<select id="selectByNameAndSex" resultType="Student">select * from t_student where name = #{name} and sex = #{sex}</select>

再次运行刚才的测试代码
运行结果
在这里插入图片描述
可以看出我们的@Param起作用了

核心:@Param(“这⾥填写的其实就是map集合的key”)
希望通过这篇文章大家都可以对MyBatis中的参数有一个更加深的理解


http://www.ppmy.cn/news/75252.html

相关文章

Postman传递@requestbody标注的List集合的传参遇到的问题

Postman传递requestbody标注的List集合的传参遇到的问题 引子如何测试以及遇到的问题参考文献 引子 我们想测试如下接口 RequestMapping(value "saveMessageRecover", method RequestMethod.POST) ResponseBody public AjaxMessage saveMessageRecover(RequestBod…

Robot Dynamics Lecture Notes学习笔记之关节空间动力学控制

提示&#xff1a;文章写完后&#xff0c;目录可以自动生成&#xff0c;如何生成可参考右边的帮助文档 关节空间动力学 关节空间动力学控制关节阻抗调节重力补偿逆动力学控制 关节空间动力学控制 目前的工业机器人几乎完全依赖于关节位置控制的概念。它们建立在PID控制器的基础…

(学习日记)AD学习 #3

写在前面&#xff1a; 由于时间的不足与学习的碎片化&#xff0c;写博客变得有些奢侈。 但是对于记录学习&#xff08;忘了以后能快速复习&#xff09;的渴望一天天变得强烈。 既然如此 不如以天为单位&#xff0c;以时间为顺序&#xff0c;仅仅将博客当做一个知识学习的目录&a…

认识常见中间件-redis(三)-redis缓存更新策略

redis缓存更新策略主要有三种:Cache Aside Pattern、Read/Write Through Pattern、Write Behind Caching Pattern Cache Aside Pattern&#xff08;旁路缓存&#xff09; Cache Aside策略是最常用的&#xff0c;应用程序直接与「数据库、缓存」交互&#xff0c;并负责对缓存的…

【JDK】module模块系统

JDK9新特性-module模块系统 在Sources Root下新建module-info.java&#xff0c;内容格式如下所示 module modulename {//模块指令 }modulename具有唯一性一个工程&#xff0c;即使是不同的Sources Root&#xff0c;仅能存在一个module-info.java模块体内可以保留空内容或者模…

QT客户端外包开发的特点

QT是一种跨平台的C应用程序开发框架&#xff0c;主要用于开发图形用户界面(GUI)应用程序。它提供了一套丰富的类库和工具&#xff0c;可以帮助开发者快速构建高质量、可扩展、易于维护的应用程序。今天和大家分享一下QT的主要特点和注意的问题&#xff0c;希望对大家有所帮助。…

分享7款优质免费的Figma“中文插件”

今天我要向你们分享一些 Figma 的“中文插件”&#xff0c;这些插件不仅功能强大&#xff0c;而且免费使用&#xff0c;非常方便&#xff0c;而且是完全中文的页面使用起来非常便捷&#xff0c;可以大大提高设计师的效率和体验。 1、「平面 3D」 插件 首先是平面 3D 插件。该…

ETSI TS-关于SCP80

描述 GPC_UICC Configuration_v2.0.pdf 中: 规范 ts_102.225v12.1.0 Secured packet structure for UICC based applications.pdf spi kic kid编码 7 TCP/IP 的实现 在发送安全数据包之前&#xff0c;发送实体应使用定义的推送机制打开 TCP/IP 连接 在 ETSI TS 102 226 [9] …