MyBatis的其他查询操作

前言:在上篇博客介绍了MyBatis的一些增删改查操作,接下来介绍其他查询操作


目录

1 其他查询操作

1.1 多表查询

1.1.1 准备工作

1.1.2 数据查询

1.2 #{}和${} 

1.2.1 #{}和${}使用

1.2.2 #{}和${}的区别 

1.3 排序功能 

1.4 like查询

2 数据库连接池

2.1 介绍

2.2 使用

1 其他查询操作

1.1 多表查询

多表查询和单表查询类似,只是SQL不同

1.1.1 准备工作

在用户表的基础上,再建一张文章表,用来进行多表关联查询,其中文章表的uid对应用户表的id

-- 创建⽂章表
DROP TABLE IF EXISTS articleinfo;

CREATE TABLE articleinfo (
id INT PRIMARY KEY auto_increment,
title VARCHAR ( 100 ) NOT NULL,
content TEXT NOT NULL,
uid INT NOT NULL,
delete_flag TINYINT ( 4 ) DEFAULT 0 COMMENT '0-正常, 1-删除',
create_time DATETIME DEFAULT now(),
update_time DATETIME DEFAULT now()
) DEFAULT charset 'utf8mb4';
-- 插⼊测试数据
INSERT INTO articleinfo ( title, content, uid ) VALUES ( 'Java', 'Java正⽂', 1);
@Data
public class ArticleInfo {
    private Integer id;
    private String title;
    private String content;
    private Integer uid;
    private Integer deleteFlag;
    private Date createTime;
    private Date updateTime;
    //用户的相关信息
    private String username;
    private Integer age;
    private Integer gender;
}

1.1.2 数据查询

接口定义:

@Mapper
public interface ArticleInfoMapper {
    @Select("select ta.id,ta.title,ta.content,ta.uid,tb.username,tb.age,tb.gender " +
            " from articleinfo ta LEFT JOIN userinfo tb ON ta.uid=tb.id where ta.id=1")
    ArticleInfo selectArticleAndUserById(Integer id);
}

测试代码:

@Slf4j
@SpringBootTest
class ArticleInfoMapperTest {
    @Autowired
    private ArticleInfoMapper articleInfoMapper;
    @Test
    void selectArticleAndUserById() {
        ArticleInfo articleInfo = articleInfoMapper.selectArticleAndUserById(1);
        log.info(articleInfo.toString());
    }
}

1.2 #{}和${} 

MyBatis参数赋值有两种方式,前面使用了#{ }进行赋值,接下来看一下两者的区别

1.2.1 #{}和${}使用

1 Integer类型的参数

@Mapper
public interface UserInfoMapper {
    @Select("select username,password,age,gender,phone from userinfo where id=#{id}")
    UserInfo selectId(Integer id);
}
@Test
void selectId() {
    UserInfo userInfo = userInfoMapper.selectId(1);
    log.info(userInfo.toString());
}

 从打印的日志可以看出,输入的参数并没有再后面进行拼接,id的值是使用?进行占位,这种SQL称之为"预编译SQL"

将#{}改为${}再观察打印日志

@Mapper
public interface UserInfoMapper {
    @Select("select username,password,age,gender,phone from userinfo where id=${id}")
    UserInfo selectId(Integer id);
}

可以看到,参数是直接拼接再SQL语句中了,这种SQL称之为"即时SQL"

2 String类型的参数

@Mapper
public interface UserInfoMapper {
    @Select("select username,password,age,gender,phone from userinfo where username=#            
    {username}")
    UserInfo selectId(String username);
}
@Test
void selectId() {
    UserInfo userInfo = userInfoMapper.selectId("admin");
    log.info(userInfo.toString());
}

可以看到结果正常返回了 

将#{}改为${}再观察打印日志

@Mapper
public interface UserInfoMapper {
    @Select("select username,password,age,gender,phone from userinfo where 
    username=${username}")
    UserInfo selectId(String username);
}

从日志可以看出,这次的参数依然是直接拼接在SQL语句中了,但是字符串作为参数时,需要添加' ',使用${ }不会拼接' ',导致程序报错

修改代码如下:

@Mapper
public interface UserInfoMapper {
    @Select("select username,password,age,gender,phone from userinfo where 
    username='${username}'")
    UserInfo selectId(String username);
}

从上面两个例子可以看出:

#{ }使用的是预编译SQL, 通过?占位的方式,提前对SQL进行编译,然后把参数填充到SQL语句中,#{ }会根据参数的类型,自动拼接' '

${ }会直接进行字符串替换,仪器对SQL进行编译,如果参数为字符串,需要手动添加' '

1.2.2 #{}和${}的区别 

#{ }和${ }的区别就是预编译SQL即时SQL的区别

1)预编译SQL的性能更高

预编译SQL在编译一次之后会将编译后的SQL语句缓存起来,后面再执行这条语句时,不会再次编译,省去了解析优化等待过程,以此提高效率

2)预编译SQL更安全,不存在SQL注入的问题 

SQL注入:通过操作输入的数据来修改事先定义好的SQL语句,以达到执行代码对服务器进行攻击的方法

SQL注入代码:' or 1='1

正常情况:

@Mapper
public interface UserInfoMapper {
    @Select("select username,password,age,gender,phone from userinfo where 
    username='${username}'")
    UserInfo selectId(String username);
}
@Test
void selectId() {
    UserInfo userInfo = userInfoMapper.selectId("admin");
    log.info(userInfo.toString());
}

SQL注入场景: 

@Test
void selectId() {
    UserInfo userInfo = userInfoMapper.selectId("'or 1='1");
    log.info(userInfo.toString());
}

可以看出结果被查询出来了,其中参数 or 被当作SQL语句的一部分,此时查询的数据并不是想要的数据,所以用于查询的字段,尽量使用#{ }预查询的方式 

SQL注入是一种非常常见的数据库攻击手段,如果发生在用户登录的场景中,密码为' or 1='1就可能完成登录

1.3 排序功能 

从上面的例子可以得出:${ }会有SQL注入的风险,所以尽量使用#{ }完成查询,那么是不是${ }就没有作用了呢,因此,接下来看下${ }的使用场景

@Select("select id,username,age,gender,phone,delete_flag,create_time,update_time " +
        " from userinfo order by id ${sort}")
List<UserInfo> selectBySort(String sort);
@Test
void selectBySort() {
    List<UserInfo> userInfoList = userInfoMapper.selectBySort("desc");
    log.info(userInfoList.toString());
}

此处的sort参数类型为String类型,但是在SQL语句中,排序的规则时不需要添加' '的,此处使用的$符号,会直接把desc拼接在SQL语句中,输出的结果就是正确的

@Select("select id,username,age,gender,phone,delete_flag,create_time,update_time " +
        " from userinfo order by id #{sort}")
List<UserInfo> selectBySort(String sort);

将$改为#再次观察

此时可以发现,#{ }会根据参数类型判断是否要加' ',由于desc是String类型,因此加上了' ',导致SQL错误

1.4 like查询

除了排序,like使用#{ }也会报错

@Select("select id,username,age,gender,phone,delete_flag,create_time,update_time " +
        " from userinfo where username like '%#{username}%'")
List<UserInfo> selectByLike(String username);
@Test
void selectByLike() {
    List<UserInfo> userInfoList = userInfoMapper.selectByLike("wang");
    log.info(userInfoList.toString());
}

将#改为$,再次观察 

@Select("select id,username,age,gender,phone,delete_flag,create_time,update_time " +
        " from userinfo where username like '%${username}%'")
List<UserInfo> selectByLike(String username);

此时可以正确的查出来,但是${ }存在SQL注入的问题,所以不能直接使用${ },正确的做法是使用mysql的内置函数concat()来处理

@Select("select id,username,age,gender,phone,delete_flag,create_time,update_time " +
        " from userinfo where username like CONCAT('%',#{username},'%')")
List<UserInfo> selectByLike(String username);

总结:# 和 $ 的区别

# 和 $ 的区别就是预编译SQL和即时SQL的区别

1)预编译SQL性能更高

2)预编译SQL更安全,不存在SQL注入的问题

3)排序时,不能使用 # ,表明,字段名等作为参数时,也不能使用 # 

4)模糊查询时,如果使用 # ,需要搭配mysql的内置函数 concat ,不能直接使用

在实际开发中能使用 # 就使用 # ,使用  $ 时,一定要考虑SQL注入的问题

2 数据库连接池

在使用MyBatis时,我们使用了数据库连接池技术,避免频繁的创建连接,销毁链接

2.1 介绍

数据库连接池负责分配、管理和释放数据库连接,它允许应用程序重复使用一个现有的数据库连接,而不是再重新建立一个

没有使用数据库连接池的情况:每次执行SQL语句,要先创建一个新的对象,然后执行SQL语句,SQL语句执行完,再关闭连接释放对象,这种重复的创建连接,销毁比较浪费资源

使用数据库连接池的情况:程序启动时,会在数据库连接池中创建一定数量的Connection对象,当客户端请求数据库连接池,会从数据库连接池中获取Connection对象,然后执行SQL,SQL语句执行完,再把Connection归还给连接池

使用数据库连接池的优点:

1)减少了网络开销   2)资源重用   3)提升了系统的性能

2.2 使用

常见的数据库连接池:

1)C3P0   2)DBCP  3)Druid   4)Hikari

目前流行的是Hikari,Druid

Hikari:SpringBoot默认使⽤的数据库连接池

Druid   

如果想把默认数据库连接池切换为Druid数据库连接池,只需要引入相关的依赖即可

<dependency>
    <groupId>com.alibaba</groupId>
    <artifactId>druid-spring-boot-starter</artifactId>
    <version>1.1.17</version>
</dependency>

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

C++反射之检测struct或class是否实现指定函数

目录 1.引言 2.检测结构体或类的静态函数 3.检测结构体或类的成员函数 3.1.方法1 3.2.方法2 1.引言 诸如Java, C#这些语言是设计的时候就有反射支持的。c没有原生的反射支持。并且&#xff0c;c提供给我们的运行时类型信息非常少&#xff0c;只是通过typeinfo提供了有限的…

【吃透Java手写】1- Spring(上)-启动-扫描-依赖注入-初始化-后置处理器

【吃透Java手写】Spring&#xff08;上&#xff09;启动-扫描-依赖注入-初始化-后置处理器 1 准备工作1.1 创建自己的Spring容器类1.2 创建自己的配置类 ComponentScan1.3 ComponentScan1.3.1 Retention1.3.2 Target 1.4 用户类UserService Component1.5 Component1.6 测试类 2…

AI实景自动无人直播软件:引领直播行业智能化革命;提升直播效果,无人直播软件助力智能讲解

随着科技的快速发展&#xff0c;AI实景自动无人直播软件正在引领直播行业迈向智能化革命。它通过智能讲解、一键开播和智能回复等功能&#xff0c;为商家提供了更高效、便捷的直播体验。此外&#xff0c;软件还支持手机拍摄真实场景或搭建虚拟场景&#xff0c;使直播画面更好看…

Unity 性能优化之动态批处理(四)

提示&#xff1a;仅供参考&#xff0c;有误之处&#xff0c;麻烦大佬指出&#xff0c;不胜感激&#xff01; 文章目录 前言一、动态合批是什么&#xff1f;二、使用动态批处理1.打开动态合批2.满足条件 三、检查动态合批是否成功五、动态合批弊端总结 前言 动态批处理是常用优…

Flutter笔记:手动配置VSCode中Dart代码自动格式化

Flutter笔记 手动配置VSCode中Dart代码自动格式化 - 文章信息 - Author: 李俊才 (jcLee95) Visit me at CSDN: https://jclee95.blog.csdn.netMy WebSite&#xff1a;http://thispage.tech/Email: 291148484163.com. Shenzhen ChinaAddress of this article:https://blog.csd…

pcm转MP3怎么转?只需3个步骤~

PCM&#xff08;Pulse Code Modulation&#xff09;是一种用于数字音频编码的基础技术&#xff0c;最早起源于模拟音频信号数字化的需求。通过PCM&#xff0c;模拟音频信号可以被精确地转换为数字形式&#xff0c;为数字音频的发展奠定了基础。 MP3文件格式的多个优点 MP3的优…

【深度学习】网络安全,SQL注入识别,SQL注入检测,基于深度学习的sql注入语句识别,数据集,代码

文章目录 一、 什么是sql注入二、 sql注入的例子三、 深度学习模型3.1. SQL注入识别任务3.2. 使用全连接神经网络来做分类3.3. 使用bert来做sql语句分类 四、 深度学习模型的算法推理和部署五、代码获取 一、 什么是sql注入 SQL注入是一种常见的网络安全漏洞&#xff0c;它允许…

模糊的图片文字,OCR能否正确识别?

拍照手抖、光线不足等复杂的环境下形成的图片都有可能会造成文字模糊&#xff0c;那这些图片文字对于OCR软件来说&#xff0c;是否能否准确识别呢&#xff1f; 这其中的奥秘&#xff0c;与文字的模糊程度紧密相连。想象一下&#xff0c;如果那些文字对于我们的双眼来说&#x…

sed小实践2(随手记)

删除/etc/passwd的第一个字符 #本质是利用sg替换&#xff0c;将第一个字符替换成空 sed s|^.||g /etc/passwd删除/etc/passwd的第二个字符 sed -r s|^(.).(.*$)|\1\2|g /etc/passwd sed -r s|^(.).|\1|g /etc/passwd删除/etc/passwd的最后一个字符 sed s|.$||g /etc/passwd删…

Java快速入门系列-11(项目实战与最佳实践)

第十一章&#xff1a;项目实战与最佳实践 11.1 项目规划与需求分析项目规划需求分析实例代码 11.2 系统设计考虑实例代码 11.3 代码实现与重构实例代码 11.4 性能优化与监控实例代码 11.5 部署与持续集成/持续部署(CI/CD)实例代码 11.1 项目规划与需求分析 在进行任何软件开发…

基于Vumat的修正JC本构模型的切削研究

JC渐进损伤本构是研究切削中的重要本构模型&#xff0c;主要包括材料硬化和损伤两部分&#xff1a;其中&#xff0c;原始JC的硬化部分本构为&#xff1b; 添加图片注释&#xff0c;不超过 140 字&#xff08;可选&#xff09; 材料屈服应力的硬化解耦为三部分独立的效应&#x…

blender导出gltf模型混乱

最近用户给了几个blender文件&#xff0c;在blender打开是这样的&#xff1a; 我导出成gltf候&#xff0c;在本地打开时&#xff0c;底部发生了改变&#xff1a; 可以看出来&#xff0c;底部由原来的类型box变为了两个平面&#xff0c;后来我查了下blender里的属性设置&#xf…

文件IO-使用dup2实现错误日志功能及判断文件权限,并终端输出

1&#xff1a;使用 dup2 实现错误日志功能 使用 write 和 read 实现文件的拷贝功能&#xff0c;注意&#xff0c;代码中所有函数后面&#xff0c;紧跟perror输出错误信息&#xff0c;要求这些错误信息重定向到错误日志 err.txt 中去 代码&#xff1a; #incl…

后教培时代的新东方,正在找寻更大的教育驱动力?

近段时间&#xff0c;K12教育主要上市公司的阶段性业绩皆已出炉。从具体数据来看&#xff0c;随着时间推移&#xff0c;教培机构的转型之路已愈走愈顺。 财报显示&#xff0c;2023年12月1日-2024年2月29日&#xff0c;好未来实现营收4.3亿美元&#xff0c;同比增长59.7%&#…

GIS 中的空间模式

空间模式显示了地球上事物的相互联系方式。这些图案可以是天然的或人造的。当我们使用 GIS 时&#xff0c;我们可以看到事物的位置以及它们之间的关系。今天&#xff0c;让我们关注地理和 GIS 领域的空间模式。 点分布的类型 点分布是将特定位置映射为地图上的单个点的方式。这…

W801学习笔记二十四:NES模拟器游戏

之前已经实现了NES模拟器玩游戏。W801学习笔记九&#xff1a;HLK-W801制作学习机/NES游戏机(模拟器) 现在要在新版本掌机中移植过来。 1、把NES文件都拷贝到SD卡中。 这回不会受内存大小限制了。我这里拷贝了4个&#xff0c;还可以拷贝更多。 2、应用初始化中&#xff0c;加载…

【运维网络篇】史上最全的 网络知识 思维导图!

01 TCP/IP网络协议栈 02 TCP/IP协议层次划分 03 传输介质简介 04 以太网帧结构 05 IP编址 06 ICMP协议 07 ARP协议 08 传输层协议 09 路由基础 10 静态路由基础 11 距离矢量路由协议——RIP 12 链路状态路由协议——OSPF 13 HDLC&PPP原理与应用 14 帧中继…

创新指南|创新组合管理的7个陷阱以及如何避免它们

进入未知领域的第一步可能具有挑战性。尽管创新会犯错误&#xff0c;但在将 IPM 作为公司实践实施时&#xff0c;您可以准备好并避免一些常见的陷阱。在这篇文章中&#xff0c;我们将讨论组织在实施创新组合管理时遇到的最常见的陷阱。 01. 在映射中包含日常业务任务 映射中的…

【iOS】-- 内存五大分区

【iOS】-- 内存五大分区 内存五大分区1.栈区优点&#xff1a; 2.堆区优点&#xff1a; 3.全局区4.常量区5.代码区 验证static、extern、const关键字比较1.static关键字static关键字的作用&#xff1a;全局静态变量局部静态变量 2.extern关键字对内的全局变量对外的全局变量 3.c…

Intel® Platform Firmware Resilience (Intel® PFR):英特尔® 平台固件恢复力(Intel® PFR)

为了降低与固件相关的安全风险&#xff0c;英特尔为服务器平台开发了英特尔平台固件恢复力&#xff08;Intel PFR&#xff09;。 此功能可保护关键固件在启动和运行时免受攻击。这可以被视为是 Cerberus 项目或 NIST SP800-193 的实现。 英特尔平台固件恢复力&#xff08;Int…
最新文章