MyBatis:查询与连接池

一、查询

1、多表查询

尽量避免使用多表查询,尤其是对性能要求较高的项目。因为多表查询必然会导致性能变低。

例如:select *from ta运行需要10ms,select *from tb 运行也需要10s。但是,select *from ta left join tb on ta.xx==tb.xx 必然大于10ms,

并且数据库集群是很多项目一起使用的,当出现慢查询时,会影响整个集群,也就是会影响其他服务的速度。

在数据库上再建立一个文章表:

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 CURRENT_TIMESTAMP,update_time DATETIME DEFAULT CURRENT_TIMESTAMP
) DEFAULT CHARSET = 'utf8mb4';INSERT INTO articleinfo (title, content, uid) VALUES ('Java', 'Java正文', 1);
INSERT INTO articleinfo (title, content, uid) VALUES ('Python', 'Python正文', 2);

对应Model层的实体类:

package com.example.mybatisdemo.model;import lombok.Data;import java.util.Date;@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;
}

根据uid查询作者的名称等相关信息,进行多表查询的sql语句应该为:

SELECT ta.*, tb.username
FROM articleinfo ta
LEFT JOIN userinfo tb ON ta.uid = tb.id
WHERE ta.id = 1;

所以,我们要补充实体类,在刚刚的ArticleInfo类中加入用户相关信息,便于映射:

@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;
}

对应的ArticlenInfoMapper接口:

@Mapper
public interface ArticlenInfoMapper {//多表查询@Select("select ta.*,tb.username from articleinfo ta " +"left join userinfo tb on ta.uid = tb.id " +"where ta.id = #{articleId}")ArticleInfo selectArticlenAndUserByID(Integer articleId);
}

如果名称不⼀致的,采⽤ResultMap,或者别名的方式解决, 和单表查询⼀样。Mybatis 不管单表还是多表,主要就是三部分:SQL, 映射关系和实体类通过映射关系,把SQL运⾏结果和实体类关联起来。

2、#{} 和 ${}

Ⅰ、区别

#{}和${}都是MyBatis框架中使用的占位符。

@Select("select username, `password`, age, gender, phone from userinfo where username= #{name} ")
UserInfo selectByName(String name);

image-20240319102440963

然后把#{}换成${}

@Select("select username, `password`, age, gender, phone from userinfo where username= ${name} ")
UserInfo selectByName(String name);

image-20240319102604288

使用${}时,MyBatis不会自动添加引号。{}用于直接替换SQL语句中的文本,因此在某些情况下,如果替换的值是字符串,则需要手动添加引号。

#{}利用预编译SQL的方式工作,它通过在SQL语句中使用?占位符来提前编译SQL命令,并在执行时将参数值安全地绑定到这些占位符上。MyBatis会根据参数的类型自动添加必要的引号,例如字符串类型的参数会被加上引号'',以确保SQL语句的正确性和安全性。相反,${}则采用简单的字符串替换机制,它在SQL语句编译之前直接将参数值替换到SQL命令中。这意味着如果参数值是字符串,需要手动添加引号''来确保SQL语句的语法正确性。

总结:

#{}${}在MyBatis中的区别主要体现在以下几个方面:

  1. 预编译处理
    • #{}:使用预编译语句(PreparedStatement),参数会被替换为?,并在SQL执行时绑定参数值。这种方式可以防止SQL注入,因为参数值会被数据库引擎视为数据,而不是SQL命令的一部分。
    • ${}:不使用预编译语句,参数值会直接替换到SQL语句中。这种方式不会防止SQL注入,因为参数值被视为SQL语句的一部分,如果参数值中包含SQL关键字或特殊字符,可能会改变原SQL语句的结构。
  2. 参数替换方式
    • #{}:参数替换后,MyBatis会根据参数的类型自动添加引号,例如字符串类型的参数会被加上引号''
    • ${}:参数替换后,不会自动添加引号,如果参数是字符串类型,需要手动添加引号。
  3. 使用场景
    • #{}:适用于大部分情况,尤其是处理用户输入或不可信数据时,提供安全保障。
    • ${}:适用于需要动态指定表名、列名或其他SQL关键字的情况,但使用时需要确保参数值的安全性。
  4. 性能影响
    • #{}:通常不会对性能产生负面影响,因为预编译语句可以被数据库缓存和重用。
    • ${}:如果用于字符串替换,可能会导致数据库无法有效缓存执行计划,从而影响性能。
  5. 安全性
    • #{}:提供了更好的安全性,可以防止SQL注入攻击。
    • ${}:存在SQL注入的风险,应该尽量避免使用,或者在确保参数值安全的情况下谨慎使用。

Ⅱ、SQL注入

${}存在一个非常大的问题,那就是SQL注入。当使用${}时,MyBatis不会对替换的参数值进行任何转义或预处理。这意味着,如果参数值包含特殊字符或SQL关键字,它们将直接插入到SQL语句中。如果这些值来自于用户的输入,且没有得到适当的验证和清理,攻击者就可以利用这一点来执行恶意SQL代码。

    @Select("select * from userinfo where username like '${username}'")List<UserInfo> selectUserByName(String username);

测试代码:

@Test
void selectUserByName() {log.info(userInfoMap.selectUserByName("' or 1 = '1").toString());
}

image-20240319112222814

SQL注⼊代码: ' or 1='1。这里可以看见,结果被正确查询出来了, 其中参数 or 被当做了SQL语句的⼀部分。由于没有对用户输⼊进行充分检查,而SQL⼜是拼接⽽成,在用户输⼊参数时,在参数中添加⼀些SQL关键字,达到改变SQL运行结果的目的,也可以完成恶意攻击。

3、排序查询

@Select("SELECT id, username, age, gender, phone, delete_flag, create_time, update_time " +"FROM userinfo " +"ORDER BY id ${sort}")
List<UserInfo> selectAllUserBySort(String sort);

这里使用 ${sort} 可以实现排序查询,而使用#{sort} 就不能实现排序查询。因为,此处 sort 参数为String类型,但是SQL语句中,排序规则是不需要加引号 '' 的,所以此时的${sort} 也不加引号。如果此时,使用 #{sort} 查询时, sort参数前后会自动给加了引号, 导致出现 sql 错误。

4、模糊查询

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

和前面的排序查询一样,在这个查询中,由于#{}的工作方式,MyBatis会把'%#{key}%'当作一个整体,所以 '%#{key}%' 的预期结果是,参数key被包围在两个%通配符之间。所以,当使用like查询的时候,应该使用${},但是这样又会出现SQL注入的安全问题。

为了解决这个问题,可以使用MySQL 的CONCAT函数来动态地构造like查询的参数,像这样:

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

CONCAT是MySQL中的一个函数,用于将两个或多个字符串连接在一起。

基本的语法:CONCAT(string1, string2, ..., string_n)

like查询中,你可以使用CONCAT函数来动态地构造查询参数。例如,以下查询将查找用户名包含关键词"John"的所有用户:

SELECT * FROM user WHERE username LIKE CONCAT('%', 'John', '%');

在这个例子中,CONCAT('%', 'John', '%')将返回字符串"%John%“,这将在任意位置匹配关键词"John”。

二、数据库连接池

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

image-20240319124043111

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

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

目前比较流行的是:Hikari,Druid

  1. Hikari : SpringBoot默认使用的数据库连接池
  2. Druid:阿里巴巴开源的数据库连接池

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

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

学习文档:常见问题 · alibaba/druid Wiki (github.com)

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

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

相关文章

zabbix监控vmware esxi

一、zabbix服务端配置 修改zabbix_server.conf配置文件 vim /etc/zabbix/zabbix_server.conf #######zabbix_server.conf底部第二行开始添加下面配置######## StartVMwareCollectors5 #StartVMwareCollectors - 预先启动Vmware collector收集器实例的数量。此值取决于要监控的…

GEE显示研究区sentinel-2每年可用影像

第一次使用GEE&#xff0c;用了别人的代码&#xff0c;想查看每年影像可用数量&#xff0c;但是老是报错&#xff0c;说是null geometry&#xff0c;之前我是用GAMMA软件导出的kml文件&#xff0c;后面在arcgis自己勾画了sho文件&#xff0c;线类型&#xff0c;然后我就在想会不…

MySQL进阶-----索引的结构与分类

目录 前言 一、认识索引 二、索引结构 1.概述 2. 二叉树 3 .B-Tree 4.BTree 5.Hash 三、索引的分类 1 .索引分类 2 .聚集索引&二级索引 前言 索引&#xff08;index&#xff09;是帮助MySQL高效获取数据的数据结构(有序)。在数据之外&#xff0c;数据库系统还维…

【第十二届“泰迪杯”数据挖掘挑战赛】【2024泰迪杯】B题基于多模态特征融合的图像文本检索—解题全流程(持续更新)

2024 年(第 12 届)“泰迪杯”数据挖掘挑战赛B题 解题全流程&#xff08;持续更新&#xff09; -----基于多模态特征融合的图像文本检索 一、写在前面&#xff1a; ​ 本题的全部资料打包为“全家桶”&#xff0c; “全家桶”包含&#xff1a;模型数据、全套代码、训练好的模…

OpenLayers基础教程——使用WebGLPoints加载海量点数据

1、前言 最近遇到一个问题&#xff1a;如何在OpenLayers中高效加载海量的场强点&#xff1f;由于项目中的一些要求&#xff0c;不能使用聚合的方法加载。一番搜索之后发现&#xff1a;OpenLayers中有一个WebGLPoints类&#xff0c;使用该类可以轻松应对几十万的数据量&#xf…

汽车后视镜反射率检测光纤光谱仪:安全驾驶的守护神

在汽车的日常使用中&#xff0c;后视镜扮演着至关重要的角色。它不仅帮助驾驶员观察车辆后方的情况&#xff0c;还确保了行车的安全性。然而&#xff0c;由于各种原因&#xff0c;后视镜的反射率可能会降低&#xff0c;从而影响到驾驶员的视线范围和判断能力。为了解决这一问题…

windows允许指定IP段访问本地端口

虚拟机内部应用有时候需要访问windows的一些端口&#xff0c;例如数据库或Redis等&#xff0c;默认情况下&#xff0c;需关闭windows上的防火墙才可正常访问。本文通过在防火墙设置允许指定IP段进行访问来处理&#xff0c;不用每次操作都关闭防火墙。 入站规则-》新建规则 完成…

软考高项总结:第16章采购管理(二)

一、实施采购 1、实施采购过程的数据流向图 2、实施采购ITO 3、采购文档,是用于达成法律协议的各种书面文件,可包括: (1)招标文件:包括发给卖方的信息邀请书、建议邀请书、报价邀请书,或其他文件,以便卖方编制应答文件。 (2)采购工作说明书:向卖方清晰地说明目标…

掌握了这个分析方法,实现传输线阻抗5%的加工公差不是梦!

高速先生成员--黄刚 传输线阻抗控制对系统性能的重要性不言而喻&#xff0c;每一家的PCB加工板厂都在往能控制更严格的阻抗公差这个目标而不断努力。但是我们也知道&#xff0c;传输线阻抗的控制公差其实会受到PCB结构本身的因素影响&#xff0c;就好像下面这张PCB差分线的切片…

Nextcloud激活被锁用户

Nextcloud激活用户 如果docker下没有安装sudo 和 vim执行下面命令&#xff0c;安装了则跳过 #进入docker内部 #更新apt-get apt-get update #安装sudo apt-get install sudo #安装vim apt-get install vim 修改下面文件内容&#xff0c;否则执行occ命令可能报错 进入上面查询…

【zlm】问题记录:chrome更新引起的拉不出webrtc; 证书校验引起的放几秒中断

目录 chrome更新引起的拉不出webrtc 证书校验引起的放几秒中断 chrome更新引起的拉不出webrtc 【zlm】最新的chrome版本中的报错&#xff1a; 我有个问题event.js:8 [RTCPusherPlayer] DOMException: Failed to execute setRemoteDescription on RTCPeerConnection: Failed …

产品推荐 | 基于EV10AQ190的多通道 最大5Gsps 10bit AD FMC子卡

一、板卡概述 FMC147是一个四通道多模式AD子卡&#xff0c;完全符合VITA 57.1标准。该卡提供4个10位ADC通道&#xff0c;支持采样4、2、或1通道,采样速率为5Gsps、2.5 GSPS、1.25Gsps选择。 采样时钟可以通过一个同轴电缆连接外部提供&#xff0c;或由内部时钟源&#xff08;可…

学习笔记Day15:Shell脚本编程

Shell脚本编程 Linux系统环境 Linux系统的4个主要部分&#xff1a;内核、shell、文件系统和应用程序。 内核是操作系统的核心&#xff0c;决定系统性能和稳定性shell &#xff1a;一种应用程序&#xff0c;是用户和内核交互操作的接口&#xff0c;是套在内核外的壳&#xff…

C++函数模板详解(结合代码)

目录 1. 模板概念 2. 函数模板语法 3. 函数模板注意事项 4. 函数模板案例 5. 普通函数与函数模板的区别 6. 普通函数与函数模板的调用规则 7. 模板的局限性 1. 模板概念 在C中&#xff0c;模板是一种通用的程序设计工具&#xff0c;它允许我们处理多种数据类型而不是固…

Symbol 类型必知必会

一. Symbol的概念 Symbol 是 JavaScript 中的一种新的基本数据类型&#xff0c;引入自 ECMAScript 6&#xff08;ES6&#xff09;标准。它是一种不可变且唯一的数据类型&#xff0c;可以用来创建独一无二的键&#xff08;key&#xff09;。 Symbol 的创建方式是通过调用全局的…

测试开发工程师(QA)职业到底需要干些什么?part4:安全QA

安全测试开发QA工作的主要目标是确保软件、应用程序或系统在安全方面的健壮性和可靠性。以下是安全测试开发QA工作中的一些常见任务和职责&#xff1a; 安全测试计划和策略&#xff1a;安全测试开发QA团队负责制定全面的安全测试计划和策略。他们会评估应用程序或系统的安全需求…

【优选算法】专题1 -- 双指针 -- 复写0

前言&#xff1a; 补充一下前文没有写到的双指针入门知识&#xff1a;专题1 -- 双指针 -- 移动零 目录 基础入门知识&#xff1a; 1. 复写零&#xff08;easy&#xff09; 1. 题⽬链接&#xff1a;1089.复习0 - 力扣&#xff08;LeetCode&#xff09; 2. 题⽬描述&#xff…

数据容器-dict以及总结-Python

师从黑马程序员 字典的定义 同样使用{},不过存储的元素是以个个的&#xff1a;键值对&#xff0c;如下语法&#xff1a; #定义字典 my_dict1{"王力宏":99,"周杰伦":88,"林俊杰":77} #定义空字典 my_dict2{} my_dict3dict() print(f"字典1…

springboot 将manage关闭。

这是SpringBoot自带的接口&#xff0c;会将所有的接口暴露在外面。所以我们上生产环境&#xff0c;需要将这个接口给关闭。 默认是 management.endpoints.web.exposure.include* 只需将配置文件改成下面&#xff0c;Springboot自带的接口就会关闭。 management.endpoints.…

【物联网开源平台】tingsboard二次开发

别看这篇了&#xff0c;这篇就当我的一个记录&#xff0c;我有空我再写过一篇&#xff0c;编译的时候出现了一个错误&#xff0c;然后我针对那一个错误执行了一个命令&#xff0c;出现了绿色的succes,我就以为整个tingsboard项目编译成功了&#xff0c;后面发现的时候&#xff…