【MyBatis】篇二.MyBatis查询与特殊SQL
文章目录
- 1、MyBatis获取参数值
- case1-单个字面量类型的参数
- case2-多个字面量类型的参数
- case3-map集合类型的参数
- case4-实体类类型的参数
- case5-使用@Param注解命名参数
- 总结
- 2、MyBatis的各种查询功能
- case1-查询结果是一个实体类对象
- case2-查询结果是一个List集合
- case3-查询单个数据
- case3-查询一条数据为Map集合
- case4-查询多条数据为Map集合
- 3、特殊SQL的执行
- case1-模糊查询
- case2-批量删除
- case3-动态设置表名
- case4-添加功能获取自增的主键
1、MyBatis获取参数值
MyBatis获取参数值有两种方式:${} 和 #{}
- ${}的本质是字符串拼接
- #{}的本质是占位符赋值
- 为字符串类型或日期类型的字段进行赋值时,拼接的${}需要手动加单引号,占位符则不用
case1-单个字面量类型的参数
当mapper接口的方法的参数是单个的字面量类型:
package com.llg.mybatis.mapperpublic interface UserMapper{/*** 根据用户名获取用户信息*/User getUserByUsername(String username);
}
映射文件:
<!--User getUserByUsername(String username);-->
<select id="getUserByUsername" resultType="User">select * from t_user where username = #{username}
</select>
<!--User getUserByUsername(String username);-->
<select id="getUserByUsername" resultType="User"> select * from t_user where username = '${username}'
</select>
当mapper接口的方法的参数是单个的字面量类型:此时可以使用${}和#{}以任意的名称(最好见名识意)获取参数的值,注意${}需要手动加单引号

贴个坑:
当mapper的方法参数是基础类型且只有一个时,在mapper.xml文件中使用${}取值时,会报There is no getter for property named ‘id’ in 'class java.lang.xx’异常
解决方法:--@Param注解public AreaDict selectById(@Param("id") Integer id);
select * from area_dict where area_dict_id = ${id}--将${}换成#{}取值,#{}能防止sql注入,${}只是简单的字符串替换,#{}先进行预处理select * from area_dict where area_dict_id = #{id}--通过${value}或${_parameter}取值select * from area_dict where area_dict_id = ${_parameter}
select * from area_dict where area_dict_id = ${value}

case2-多个字面量类型的参数
package com.llg.mybatis.mapperpublic interface UserMapper{/*** 通过用户名和密码验证登录*/User checkLogin(String username,String password);
}
-
若mapper接口中的方法参数为多个时,此时MyBatis会自动将这些参数放在一个map集合中,以两种方式进行存储:
。以arg0,arg1…为键,以参数为值
。以param1,param2…为键,以参数为值 -
通过${}和#{}访问map集合的键就可以获取相对应的值,注意${}需要手动加单引号
-
使用arg或者param都行,要注意的是,arg是从arg0开始的,param是从param1开始的
<!--User checkLogin(String username,String password);-->
<select id="checkLogin" resultType="User"> select * from t_user where username = #{arg0} and password = #{arg1}
</select>
<!--User checkLogin(String username,String password);-->
<select id="checkLogin" resultType="User">select * from t_user where username = '${param1}' and password = '${param2}'
</select>

case3-map集合类型的参数
参考case2的底层原理:若mapper接口方法的参数有多个时,可以手动将这些参数放在一个自己定义的map中存储,此时方法的传参类型为map集合,键名自己定义。
public interface UserMapper{/*** 验证登录(传参为map集合)*/User checkLoginByMap(Map<String,Object> map);
}
@Test
public void checkLoginByMap() {SqlSession sqlSession = SqlSessionUtils.getSqlSession();UserMapper mapper = sqlSession.getMapper(UserrMapper.class);Map<String,Object> map = new HashMap<>();map.put("usermane","admin");map.put("password","admin123");User user = mapper.checkLoginByMap(map);System.out.println(user);
}
此时,获取参数值仍是通过#{}或者${}访问map集合中的键:
<!--User checkLoginByMap(Map<String,Object> map);-->
<select id="checkLoginByMap" resultType="User">select * from t_user where username = #{username} and password = #{password}
</select>
case3即case2的一种演变,不同的是我们手动创建了一个map集合,访问的是我们自己定义的键。
case4-实体类类型的参数
mapper接口方法的参数是实体类类型的参数:
public interface UserMapper{/*** 添加用户信息*/int insertUser(User user);
}
mapper接口中方法的参数是实体类类型,此时可用#{}或者${},通过实体类中的属性名访问属性值。
<!--int insertUser(User user);-->
<insert id="insertUser">insert into t_user values(null,#{username},#{password},#{age},#{sex},#{email})
</insert>
测试:
@Test
public void testInsertUser() {SqlSession sqlSession = SqlSessionUtils.getSqlSession();UserMapper mapper = sqlSession.getMapper(UserMapper.class);User user = new User(null,"llg","llg123",23,"男","llg@qq.com");mapper.insertUser(user);
}
case5-使用@Param注解命名参数
加入@Param注解后,MyBatis就会将这些参数放在Map集合中,以两种方式进行存储:
- 以@Param注解括号中的值为键,以方法的参数为值
- 以自己的方式来设置键名,即param1、param2。以参数为值
因此只需通过#{}和${},以键的方式访问值即可。
public interface UserMapper{/*** 验证登录(使用@Param注解)*/User checkLoginByParam(@Param("username") String username,@Param("password") String password);
}
这是case2和3的结合,不用我们自己创建Map集合,而键名又可以自己定义。
<!--User CheckLoginByParam(@Param("username") String username, @Param("password") String password);--><select id="CheckLoginByParam" resultType="User">select * from t_user where username = #{username} and password = #{password}</select>
@Test
public void checkLoginByParam() {SqlSession sqlSession = SqlSessionUtils.getSqlSession();UserMapper mapper = sqlSession.getMapper(UserMapper.class);mapper.CheckLoginByParam("admin","admin123");
}
总结
以上情况可以整合为两种来处理:
- 实体类类型的参数
- 使用@Param注解标识参数
2、MyBatis的各种查询功能
如果查询出的数据只有一条,可以通过:
- 实体类对象接收
- List集合接收
- Map集合接收,结果{password=123456, sex=男, id=1, age=23, username=admin}
如果查询出的数据有多条,一定不能用实体类对象接收,会抛异TooManyResultsException,可以通过:
- 实体类类型的LIst集合接收
- Map类型的LIst集合接收,
List<Map<String,Object>> - 在mapper接口的方法上添加@MapKey注解
case1-查询结果是一个实体类对象
/*** 根据用户id查询用户信息* @param id* @return*/
User getUserById(@Param("id") int id);
<!--User getUserById(@Param("id") int id);-->
<select id="getUserById" resultType="User">select * from t_user where id = #{id}
</select>
case2-查询结果是一个List集合
/*** 查询所有用户信息* @return*/
List<User> getUserList();
<!--List<User> getUserList();-->
<select id="getUserList" resultType="User">select * from t_user
</select>
case3-查询单个数据
/** * 查询用户的总记录数 * @return * 在MyBatis中,对于Java中常用的类型都设置了类型别名(类型别名不区分大小写) * 例如:java.lang.Integer-->int|integer * 例如:int-->_int|_integer * 例如:Map-->map,List-->list */
Integer getCount();
注意这里的resultType,我们需要将查询结果转换为一个int,而不是User,这里使用java.lang.Integer类的别名:
<!--int getCount();-->
<select id="getCount" resultType="_integer">select count(*) from t_user
</select>
在MyBatis中,对于Java中常用的类型都设置了类型别名:


case3-查询一条数据为Map集合
当我们查询出来的数据没有任何一个实体类可以与之对应,这个时候就可以将它转换为一个Map集合,以字段为键,以字段的值为值。
/** * 根据用户id查询用户信息为map集合 * @param id * @return */
Map<String, Object> getUserToMap(@Param("id") int id);
<!--Map<String, Object> getUserToMap(@Param("id") int id);-->
<select id="getUserToMap" resultType="map">select * from t_user where id = #{id}
</select>
<!--结果:{password=123456, sex=男, id=1, age=23, username=admin}-->
case4-查询多条数据为Map集合
- 使用Map类型的List集合:
一条数据对应一个map,若有多条数据,就会产生多个map集合,此时可以将这些map放在一个list集合中获取
/** * 查询所有用户信息为map集合 * @return */
List<Map<String, Object>> getAllUserToMap();
<!--Map<String, Object> getAllUserToMap();-->
<select id="getAllUserToMap" resultType="map"> select * from t_user
</select>
<!--结果:[{password=123456, sex=男, id=1, age=23, username=admin},{password=123456, sex=男, id=2, age=23, username=张三},{password=123456, sex=男, id=3, age=23, username=张三}]
-->
- 使用@MapKey注解
在mapper接口的方法上添加注解@MapKey,此时,将每条数据转换的map集合做为值,以某个字段的值做为键,放在同一个Map集合中
/*** 查询所有用户信息为map集合* @return* 通过@MapKey注解设置map集合的键,值是每条数据所对应的map集合*/
@MapKey("id")
Map<String, Object> getAllUserToMap();
<!--Map<String, Object> getAllUserToMap();-->
<select id="getAllUserToMap" resultType="map">select * from t_user
</select>
<!--结果:{1={password=123456, sex=男, id=1, age=23, username=admin},2={password=123456, sex=男, id=2, age=23, username=张三},3={password=123456, sex=男, id=3, age=23, username=张三}}
-->
3、特殊SQL的执行
在执行一些特殊的SQL的时候,直接使用${}或者#{}会有问题,需要额外做一些处理:
case1-模糊查询
/*** 根据用户名进行模糊查询* @param username * @return */
List<User> getUserByLike(@Param("username") String username);
映射文件:
<!--List<User> getUserByLike(@Param("username") String username);-->
<select id="getUserByLike" resultType="User"><!--select * from t_user where username like '%${adm}%'--> <!--select * from t_user where username like concat('%',#{adm},'%')--> select * from t_user where username like "%"#{adm}"%"
</select>
模糊查询的SQL三种写法:
- 使用${}获取参数
- 使用concat函数拼接
- 直接使用双引号(最常用)
select * from t_user where username like "%"#{adm}"%"
case2-批量删除
批量删除,只能使用${},若使用#{},SQL变为:
#{}自动加一个单引号,导致SQL语法错误:delete from t_user where id in ('1,2,3');
正确的SQL应为:
delete from t_user where id in (1,2,3);
delete from t_user where id in ('1','2','3');
/*** 根据id批量删除* @param ids * @return int*/
int deleteMore(@Param("ids") String ids);
<delete id="deleteMore">delete from t_user where id in (${ids})
</delete>
//测试类
@Test
public void deleteMore() {SqlSession sqlSession = SqlSessionUtils.getSqlSession();SQLMapper mapper = sqlSession.getMapper(SQLMapper.class);int result = mapper.deleteMore("1,2,3");System.out.println(result);
}
case3-动态设置表名
和批量删除一样,若表名使用#{}获取,则SQL语法错误,只能使用${}来实现:
/*** 查询指定表中的数据* @param tableName */
List<User> getUserByTable(@Param("tableName") String tableName);
<!--List<User> getUserByTable(@Param("tableName") String tableName);-->
<select id="getUserByTable" resultType="User">select * from ${tableName}
</select>
case4-添加功能获取自增的主键
业务场景:
。 添加班级信息
。 添加学生信息
。 为班级分配学生,即将某学生的班级id改为新添加的班级的id
t_class(class_id,class_name)
t_student(student_id,student_name,class_id)//一对多的关系,关联字段加在"多"的一方
Mapper接口:
/*** 添加用户信息* @param user */
void insertUser(User user);
映射文件:
<!--void insertUser(User user);-->
<insert id="insertUser" useGeneratedKeys="true" keyProperty="id">insert into t_user values (null,#{username},#{password},#{age},#{sex},#{email})
</insert>
注意两个属性:
- useGeneratedKeys:设置当前标签中的SQL使用了自增的主键
- keyProperty:将自增的主键的值赋给传输到映射文件中参数的某个属性
(因为增删改有统一的返回值是受影响的行数,因此只能将获取的自增的主键放在传输的参数user对象的某个属性中)
//测试类
@Test
public void insertUser() {SqlSession sqlSession = SqlSessionUtils.getSqlSession();SQLMapper mapper = sqlSession.getMapper(SQLMapper.class);User user = new User(null, "test2", "test123", 23, "男", "test2@qq.com");mapper.insertUser(user);System.out.println(user);//输出:user{id=10, username='ton', password='123', age=23, sex='男', email='123@321.com'},自增主键存放到了user的id属性中
}

相关文章:
【MyBatis】篇二.MyBatis查询与特殊SQL
文章目录1、MyBatis获取参数值case1-单个字面量类型的参数case2-多个字面量类型的参数case3-map集合类型的参数case4-实体类类型的参数case5-使用Param注解命名参数总结2、MyBatis的各种查询功能case1-查询结果是一个实体类对象case2-查询结果是一个List集合case3-查询单个数据…...
CE认证机构和CE证书的分类
目前,CE认证已普遍被应用在很多行业的商品中,也是企业商品进入欧洲市场的必备安全合格认证。在船舶海工行业中,也同样普遍应用,很多时候,对于规范中没有明确认证要求的设备或材料,而船舶将来还会去欧洲水域…...
Lesson 8.2 CART 分类树的建模流程与 sklearn 评估器参数详解
文章目录一、CART 决策树的分类流程1. CART 树的基本生长过程1.1 规则评估指标选取与设置1.2 决策树备选规则创建方法1.3 挑选最佳分类规则划分数据集1.4 决策树的生长过程2. CART 树的剪枝二、CART 分类树的 Scikit-Learn 快速实现方法与评估器参数详解1. CART 分类树的 sklea…...
【Unity】程序集Assembly模块化开发
笔者按:使用Unity版本为2021.3LTS,与其他版本或有异同。请仅做参考 一、简述。 本文是笔者在学习使用Unity引擎的过程中,产学研的一个笔记。由笔者根据官方文档Unity User Manual 2021.3 (LTS)/脚本/Unity 架构/脚本编译/程序集定义相关部分结…...
马尔可夫决策过程
1. 马尔可夫决策过程 马尔可夫决策过程不过是引入"决策"的马氏过程. Pij(a)P{Xn1j∣X0,a0,X1,a1,...,Xni,an1}P{Xnn1j∣Xni,ana}\begin{split} P_{ij}(a) & P\{X_{n1} j|X_0, a_0, X_1, a_1, ..., X_n i, a_n 1\} \\ &P\{X_n{n1} j|X_n i, a_n a\} \e…...
win11下载配置CIC Flowmeter环境并提取流量特征
提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档 文章目录前言一、下载CIC Flowmeter二、安装java、maven、gradle和IDEA1.java 1.82.maven3.gradle4.IDEA三、CICFlowMeter-master使用四、流量特征1.含义2.获取前言 配了一整…...
JDK如何判断自己是什么公司的
0x00 前言 因为一些事情,遇到了这样一个问题,JDK如何判断自己是什么公司编译的。因为不同的公司编译出来,涉及到是否商用收费的问题。 平时自己使用的时候,是不会考虑到JDK的编译公司是哪一个,都是直接拿起来用&#…...
大数据技术之HBase(二)HBase原理简介
一、HBase定义1.1 HBase定义HBase 是一种分布式、可扩展、支持海量数据存储的 NoSQL 数据库非结构化数据存储的数据库,基于列的模式存储。利用Hadoop HDFS作为其文件存储系统,写入性能很强,读取性能较差。利用Hadoop MapReduce来处理HBase中的…...
垒骰子(爆搜/DP)
动态规划方格取数垒骰子方格取数 题目描述 设有 NNN \times NNN 的方格图 (N≤9)(N \le 9)(N≤9),我们将其中的某些方格中填入正整数,而其他的方格中则放入数字 000。如下图所示(见样例): A0 0 0 0 0 0 0 00 0 13 0 …...
Telink之标准SDK的介绍_1
前提:常见的项目架构:应用层----》驱动层----》硬件层 1、软件组织架构 顶层⽂件夹( 8 个): algorithm,application,boot,common,drivers,proj_lib,stack,v…...
JNI内两种方式从C/C++中传递一维、二维、三维数组数据至Java层详细梳理
目录 0 前言 1 准备工作介绍 2 一维数组 2.1 return形式 2.2 参数形式 3 二维数组 3.1 return形式 3.2 参数形式 4 三维数组 4.1 return形式 4.2 参数形式 5 测试代码 6 结果说明 0 前言 就如之前我写过的一篇文章【JNI内形参从C代码中获取返回值并返回到Java层使…...
快递计费系统--课后程序(Python程序开发案例教程-黑马程序员编著-第3章-课后作业)
实例5:快递计费系统 快递行业高速发展,我们邮寄物品变得方便快捷。某快递点提供华东地区、华南地区、华北地区的寄件服务,其中华东地区编号为01、华南地区编号为02、华北地区编号为03,该快递点寄件价目表具体如表1所示。 表1 寄…...
JS - 自定义一周的开始和结束,计算日期所在月的周数、所在月第几周、所在周的日期范围
自定义一周的开始和结束,计算日期所在月的周数、所在月第几周、所在周的日期范围一. 方法使用二. 实现案例一. 方法使用 根据月开始日期星期几、月结束日期星期几,计算始周、末周占月的天数(每周周期段:上周六 —— 本周五&#x…...
Linux :理解编译的四个阶段
目录一、了解编译二、认识编译的四个阶段(一)预处理(二)编译(三)汇编(四)链接1.静态链接2.动态链接三、分步编译(一)创建.c文件(二)预…...
197.Spark(四):Spark 案例实操,MVC方式代码编程
一、Spark 案例实操 1.数据准备 电商网站的用户行为数据,主要包含用户的 4 种行为:搜索,点击,下单,支付 样例类: 2. Top10 热门品类 先按照点击数排名,靠前的就排名高;如果点击数相同,再比较下单数;下单数再相同,就比较支付数。 我们有多种写法,越往后性能越…...
Vue 项目如何迁移小程序
最近我们看到有开发者在社群里提出新的疑惑「我手头已经有一个成熟的 HTML5 项目了,这种项目可以转为小程序在 FinClip 环境中运行吗?」。 经过工作人员的沟通了解,开发者其实是想将已有的 Vue 项目转为小程序,在集成了 FinClip …...
unit1-问候以及介绍
unit1-问候以及介绍 重点表达 1、问好 使用hello 和 hi 来打招呼。hello可以使用在正式和非正式的场合。hi是非正式的。但是hello 和 hi 都可以在一天的任何时段使用。 Hello. 你好。 Hi! 嗨! 介绍你的姓名 使用 I’m 和 My name is 告诉别人你的名字。 I’m Pau…...
杂记——19.git上传时出现the remote end hung up unexpectedly错误
git是大家常用的项目版本控制工具,熟练地使用git可以提高开发效率,但是有时在使用git推送代码时,会提示“the remote end hung up unexpectedly”的问题,那么git推送代码提示“the remote end hung up unexpectedly”怎么解决呢&a…...
python123平台题目
作业二 1. 2的n次方描述输入格式输出格式输入输出实例代码解析2. 输出最大值描述输入格式输出格式输入输出示例代码解析3. 字符串输出描述输入格式输出格式输入输出示例代码解析4. 字符串长度描述输入格式输出格式输入输出示例代码解析...
ROS学习笔记(六):TF坐标变换
ROS学习笔记(六):TF坐标变换TF的基本知识TF工具tf_monitortf_echostatic_transform_publisherview_frames创建TF广播器创建TF监听器TF的基本知识 TF是一个让用户随时间跟踪多个坐标系的功能包,它使用树形数据结构,根据…...
SpringBoot-17-MyBatis动态SQL标签之常用标签
文章目录 1 代码1.1 实体User.java1.2 接口UserMapper.java1.3 映射UserMapper.xml1.3.1 标签if1.3.2 标签if和where1.3.3 标签choose和when和otherwise1.4 UserController.java2 常用动态SQL标签2.1 标签set2.1.1 UserMapper.java2.1.2 UserMapper.xml2.1.3 UserController.ja…...
【kafka】Golang实现分布式Masscan任务调度系统
要求: 输出两个程序,一个命令行程序(命令行参数用flag)和一个服务端程序。 命令行程序支持通过命令行参数配置下发IP或IP段、端口、扫描带宽,然后将消息推送到kafka里面。 服务端程序: 从kafka消费者接收…...
React第五十七节 Router中RouterProvider使用详解及注意事项
前言 在 React Router v6.4 中,RouterProvider 是一个核心组件,用于提供基于数据路由(data routers)的新型路由方案。 它替代了传统的 <BrowserRouter>,支持更强大的数据加载和操作功能(如 loader 和…...
UE5 学习系列(三)创建和移动物体
这篇博客是该系列的第三篇,是在之前两篇博客的基础上展开,主要介绍如何在操作界面中创建和拖动物体,这篇博客跟随的视频链接如下: B 站视频:s03-创建和移动物体 如果你不打算开之前的博客并且对UE5 比较熟的话按照以…...
【第二十一章 SDIO接口(SDIO)】
第二十一章 SDIO接口 目录 第二十一章 SDIO接口(SDIO) 1 SDIO 主要功能 2 SDIO 总线拓扑 3 SDIO 功能描述 3.1 SDIO 适配器 3.2 SDIOAHB 接口 4 卡功能描述 4.1 卡识别模式 4.2 卡复位 4.3 操作电压范围确认 4.4 卡识别过程 4.5 写数据块 4.6 读数据块 4.7 数据流…...
Java多线程实现之Callable接口深度解析
Java多线程实现之Callable接口深度解析 一、Callable接口概述1.1 接口定义1.2 与Runnable接口的对比1.3 Future接口与FutureTask类 二、Callable接口的基本使用方法2.1 传统方式实现Callable接口2.2 使用Lambda表达式简化Callable实现2.3 使用FutureTask类执行Callable任务 三、…...
Qt Http Server模块功能及架构
Qt Http Server 是 Qt 6.0 中引入的一个新模块,它提供了一个轻量级的 HTTP 服务器实现,主要用于构建基于 HTTP 的应用程序和服务。 功能介绍: 主要功能 HTTP服务器功能: 支持 HTTP/1.1 协议 简单的请求/响应处理模型 支持 GET…...
Docker 本地安装 mysql 数据库
Docker: Accelerated Container Application Development 下载对应操作系统版本的 docker ;并安装。 基础操作不再赘述。 打开 macOS 终端,开始 docker 安装mysql之旅 第一步 docker search mysql 》〉docker search mysql NAME DE…...
CRMEB 中 PHP 短信扩展开发:涵盖一号通、阿里云、腾讯云、创蓝
目前已有一号通短信、阿里云短信、腾讯云短信扩展 扩展入口文件 文件目录 crmeb\services\sms\Sms.php 默认驱动类型为:一号通 namespace crmeb\services\sms;use crmeb\basic\BaseManager; use crmeb\services\AccessTokenServeService; use crmeb\services\sms\…...
归并排序:分治思想的高效排序
目录 基本原理 流程图解 实现方法 递归实现 非递归实现 演示过程 时间复杂度 基本原理 归并排序(Merge Sort)是一种基于分治思想的排序算法,由约翰冯诺伊曼在1945年提出。其核心思想包括: 分割(Divide):将待排序数组递归地分成两个子…...

