【MyBatis】篇二.MyBatis查询与特殊SQL

news2025/8/6 16:00:28

文章目录

  • 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.mapper

public 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.mapper

public 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属性中
}

在这里插入图片描述

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

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

相关文章

杂记——16.idea中导入maven项目

这篇文章我们来讲一下如何从Gitee上拉取项目&#xff0c;并将该项目导入到idea中 目录 1.拉取项目 2.idea导入项目 3.更改相关的配置 3.1更改maven仓库 3.2更改数据库的连接池 1.拉取项目 第一步&#xff1a;找到相关的项目地址 如图所示&#xff0c;在Gitee上找到相关的…

FPGA时序约束(二)利用Quartus18对Altera进行时序约束

系列文章目录 FPGA时序约束&#xff08;一&#xff09;基本概念入门及简单语法 文章目录系列文章目录前言Quartus时序约束不进行时序约束的后果时序约束方法TimeQuest Timing Analyzer 工具来对工程添加约束。创建网表读取SDC文件创建时钟&#xff08;Create Clock&#xff09…

八股总结(三)操作系统内存管理、进程线程、进程同步与通信、中断与异常、常用命令

layout: post title: 八股总结&#xff08;三&#xff09;操作系统内存管理、进程线程、进程同步与通信、中断与异常、常用命令 description: 八股总结&#xff08;三&#xff09;操作系统内存管理、进程线程、进程同步与通信、中断与异常、常用命令 tag: 八股总结 文章目录操作…

基础SQL语法及使用案例

通用SQL语法 SQL语句可以单行或多行书写&#xff0c;以分号结尾。SQL语句可以使用空格/缩进来增强语句的可读性。MySOL数据库的SQL语句不区分大小写&#xff0c;关键字建议使用大写。注释&#xff1a; 单行注释&#xff1a;--注释内容 或 #注释内容(MySQL特有) 多行注释&#…

英伟达驱动爆雷?CPU占用率过高怎么办?

又有一新驱动导致CPU占用率过高&#xff1f; 上周英伟达发布531.18显卡驱动&#xff0c;为大家带来了视频超分辨率技术&#xff0c;并为新发布的热门游戏《原子之心》提供支持。 但在安装新驱动后没过不久就有玩家反映&#xff0c;在游戏结束后会出现CPU占用率突然飙升到10%以…

YOLOv5源码逐行超详细注释与解读(2)——推理部分detect.py

前言 前面简单介绍了YOLOv5的项目目录结构&#xff08;直通车&#xff1a;YOLOv5源码逐行超详细注释与解读&#xff08;1&#xff09;——项目目录结构解析&#xff09;&#xff0c;对项目整体有了大致了解。 今天要学习的是detect.py。通常这个文件是用来预测一张图片或者一…

TCL 拥抱云原生,实现 IT 成本治理优化

作者&#xff1a;行疾 TCL 工程师团队基于阿里云企业云原生 IT 成本治理方案沉淀了一套成熟的 IT 企业成本治理流程与系统&#xff0c;通过阿里云容器服务提供的开箱即用的成本洞察、资源智能画像等功能&#xff0c;进行业务成本拆分、闲置资源可视化发现&#xff0c;并制定弹性…

【开源库学习】从OkHttp到Retrofit(其二 Retrofit)

从OkHttp到Retrofit简单使用实现原理loadServiceMethodConverter简单使用 class RetrofitActivity : AppCompatActivity() {companion object {const val SERVER "https://www.xxx.com/"}var disposable:Disposable? null;override fun onCreate(savedInstanceSt…

Lesson 8.2 CART 分类树的建模流程与 sklearn 评估器参数详解

文章目录一、CART 决策树的分类流程1. CART 树的基本生长过程1.1 规则评估指标选取与设置1.2 决策树备选规则创建方法1.3 挑选最佳分类规则划分数据集1.4 决策树的生长过程2. CART 树的剪枝二、CART 分类树的 Scikit-Learn 快速实现方法与评估器参数详解1. CART 分类树的 sklea…

Linux线程概念

重新认识一下进程 在之前写过的与进程相关的博文中&#xff0c;都把进程看作是只有一个PCB的进程。如图&#xff1a; 而实际上&#xff0c;在Linux中&#xff0c;进程不止一个执行流&#xff0c;而是可能会有几个或很多个。同一个进程中&#xff0c;每一个执行流都指向同一个虚…

【C语言】3天速刷C语言(初识)

【声明】本篇博客只用于对与刚学习C语言的同学的一个初始了解&#xff0c;具体内容请继续关注本专栏后续内容。什么是C语言C语言是一门通用计算机编程语言&#xff0c;广泛应用于底层开发。C语言的设计目标是提供一种能以简易的方式编译、处理低级存储器、产生少量的机器码以及…

模仿评论样式

主要用到了padding-left把左侧的空白给留出来&#xff0c;然后把头像定位到留出的空白位置。行内对齐样式&#xff0c;使用了display:inline-flex;align-items:center;图标本来要用字体比较方便&#xff0c;暂时用的从icon font下载的svg样式写的一塌糊涂&#xff0c;一点也没考…

说说转义字符 “\”

转义字符-escape character character 表示字符&#xff0c;包含两层含义&#xff0c; 1.字母 2.符号 转义&#xff1a; 改变含义 字符&#xff1a; 字母、符号 转义字符&#xff1a; 把 字母、符号 的含义改变了注意&#xff1a;这里有 2 个常常被忽视、忽略、轻视的转义规则&…

Java类加载器原理与实践

文章目录一、Java程序启动并运行的过程二、类加载器三、Java8内置的类加载器1. AppClassLoader2. ExtClassLoader3. BootStrap ClassLoader4. 3个类加载器之间的关系四、双亲委派模型五、关键类java.lang.ClassLoader1. loadClass(..)2. denfineClass(..)3. findClass(..)4. fi…

k8s client-go源码解析之informer 一

Informer(一) 注意&#xff1a;本文内容为学习笔记&#xff0c;内容为个人见解&#xff0c;不保证准确性&#xff0c;但欢迎大家讨论何指教。 本篇为先导篇&#xff0c; 介绍informer的入口工厂函数。 informer目录结构 (仅展示部分目录&#xff0c;省略的目录相似) clien…

项目实战典型案例27——对生产环境以及生产数据的敬畏之心

对生产环境以及生产数据的敬畏之心一&#xff1a;背景介绍总结升华一&#xff1a;背景介绍 本篇博客是对项目开发中出现的对生产环境以及生产数据的敬畏之心行的总结并进行的改进。目的是将经历转变为自己的经验。通过博客的方式分享给大家&#xff0c;大家一起共同进步和提高…

SpringCloud之 Gateway路由网关

文章目录Gateway 路由网关一、部署网关&#x1f34d;①添加依赖&#x1f34d;②设置配置文件&#x1f34d;③创建启动类&#x1f34d;④路由功能配置&#x1f34d;⑤路由访问服务二、路由过滤器2.1 单个过滤器: 配置文件2.2 全局过滤器: 自定义类提示&#xff1a;以下是本篇文章…

【数据结构初阶】详解链表OJ题

目录一.删除链表中等于给定值的节点二.合并有序链表并返回三.链表的回文结构1.反转单链表2.返回非空链表的中间节点四.输出链表倒数第K个节点五.基于给定值x分割单链表六.返回两个链表的第一个中间节点一.删除链表中等于给定值的节点 我们先来看第一题(题目链接): 因为我们需…

王道《操作系统》学习(二)—— 进程管理(一)

2.1 进程的概念、组成、特征、组织 2.1.1 进程的概念 这里像QQ这个程序执行了多次&#xff0c;虽然名字一样&#xff0c;但是它们的PID不同。 2.1.2 进程的组成 &#xff08;1&#xff09;PCB &#xff08;2&#xff09;程序段 和 数据段 小例子&#xff1a;程序是如何执行的&…

Nacos实现配置中心

文章目录配置中心提供的基础功能Nacos实现配置中心1、在配置文件增加配置&#xff08;application.yml&#xff09;2、使用Value来引用配置使用配置中心&#xff0c;怎样的配置方式呢一、安装nacos二、启动服务发现1、引入依赖2、配置文件3、开启服务注册发现功能4、启动服务三…