【Spring Boot】深入解析:#{} 和 ${}

1.#{} 和 ${}的使用

1.1数据准备

1.1.1.MySQL数据准备

(1)创建数据库:

CREATE DATABASE mybatis_study DEFAULT CHARACTER SET utf8mb4;

(2)使用数据库

-- 使⽤数据数据
USE mybatis_study;

(3)创建用户表


-- 创建表[⽤⼾表]CREATE TABLE `user_info` (`id` INT ( 11 ) NOT NULL AUTO_INCREMENT,`username` VARCHAR ( 127 ) NOT NULL,`password` VARCHAR ( 127 ) NOT NULL,`age` TINYINT ( 4 ) NOT NULL,`gender` TINYINT ( 4 ) DEFAULT '0' COMMENT '1-男 2-⼥ 0-默认',`phone` VARCHAR ( 15 ) DEFAULT NULL,`delete_flag` TINYINT ( 4 ) DEFAULT 0 COMMENT '0-正常, 1-删除',`create_time` DATETIME DEFAULT now(),`update_time` DATETIME DEFAULT now() ON UPDATE now(),PRIMARY KEY ( `id` ) 
) ENGINE = INNODB DEFAULT CHARSET = utf8mb4; 

(4)添加用户信息

-- 添加⽤⼾信息
INSERT INTO mybatis_study.user_info( username, `password`, age, gender, phone )
VALUES ( 'admin', 'admin', 18, 1, '18612340001' );
INSERT INTO mybatis_study.user_info( username, `password`, age, gender, phone )
VALUES ( 'zhangsan', 'zhangsan', 18, 1, '18612340002' );
INSERT INTO mybatis_study.user_info( username, `password`, age, gender, phone )
VALUES ( 'lisi', 'lisi', 18, 1, '18612340003' );
INSERT INTO mybatis_study.user_info( username, `password`, age, gender, phone )
VALUES ( 'wangwu', 'wangwu', 18, 1, '18612340004' );

1.1.2.创建对应的实体类

实体类的属性名与表中的字段名⼀⼀对应

@Data
public class UserInfo {private Integer id;private String username;private String password;private Integer age;private Integer gender;private String phone;private Integer deleteFlag;private Date createTime;private Date updateTime;}

在这里插入图片描述
注意:在实际开发中不管什么实体类都要设置删除标志、创建时间、修改时间

1.2 获取Integer类型

1.2.1 #{}

Mapper接口:

@Mapper
public interface UserInfoMapper {// 获取参数中的 UserId@Select("select * from user_info where id = #{userId} ")UserInfo queryById(@Param("userId") Integer id);

测试代码:

@Slf4j
@SpringBootTest //启动Sring 容器
class UserInfoMapperTest {@Testvoid queryById() {UserInfo result = userInfoMapper.queryById(8);log.info(result.toString());}
}

运行结果:
在这里插入图片描述

通过日志可以发现,进行占位,传的参数进行绑定到占位符。

1.2.2 ${}

Mapper接口:

@Mapper
public interface UserInfoMapper {// 获取参数中的 UserId@Select("select * from user_info where id = ${userId} ")UserInfo queryById(@Param("userId") Integer id);

测试代码:

@Slf4j
@SpringBootTest //启动Sring 容器
class UserInfoMapperTest {@Testvoid queryById() {UserInfo result = userInfoMapper.queryById(8);log.info(result.toString());}
}

运行结果:
在这里插入图片描述

通过日志可以发现,SQL命令是完整的,因为,该方法是把字符串拼接在一起执行的。

1.3 获取String类型

1.3.1 #{}

Mapper接口:

@Mapper
public interface UserInfoMapper {// 获取参数中的 username@Select("select * from user_info where username = #{username} ")List<UserInfo> queryByUsername( String username);

测试代码:

@Slf4j
@SpringBootTest //启动Sring 容器
class UserInfoMapperTest {@Autowiredprivate UserInfoMapper userMapper;@Testvoid queryByUsername() {userMapper.queryByUsername("lisi");}
}

运行结果:
在这里插入图片描述

通过日志可以发现,进行占位,传的参数进行绑定到占位符。

1.3.2 ${}

Mapper接口:

@Mapper
public interface UserInfoMapper {// 获取参数中的 username@Select("select * from user_info where username = ${username} ")List<UserInfo> queryByUsername( String username);

测试代码:

@Slf4j
@SpringBootTest //启动Sring 容器
class UserInfoMapperTest {@Autowiredprivate UserInfoMapper userMapper;@Testvoid queryByUsername() {userMapper.queryByUsername("lisi");}
}

运行结果:报错
在这里插入图片描述
在这里插入图片描述
从SQL语句中明显的看到WHERE username 后面的字符串没有引号,导致报错。

因为,${}直接把字符内容直接放进SQL语句中而没有加单引号。

修改后的mapper接口:

@Mapper
public interface UserInfoMapper {// 获取参数中的 username@Select("select * from user_info where username = '${username}' ")UserInfo queryByUsername( String username);

在这里插入图片描述

2.#{} 和 ${}的区别

2.1 预编译SQL和即时SQL的执行过程

2.1.1 预编译SQL执行过程

#{}是预编译SQL

第一步:数据库客户端(如 JDBC 驱动)将 SQL 模板发送到数据库服务器。

// SQL模版
PreparedStatement pstmt = connection.prepareStatement("SELECT * FROM user WHERE id = ? AND name = ?");

第二步:SQL 预编译
(1)数据库解析 SQL 模板,生成执行计划(包括语法检查、语义分析、优化等),并缓存该计划。
(2)此时,占位符 ? 的具体值尚未填充,数据库只处理 SQL 的结构。

第三步:客户端通过 PreparedStatement 的方法设置参数值

//参数值以二进制形式单独发送到数据库,不会直接拼接到 SQL 中,避免了 SQL 注入
pstmt.setInt(1, 123);    // 绑定 id
pstmt.setString(2, "Alice"); // 绑定 name

第四步:SQL 执行
(1)数据库使用缓存的执行计划,将绑定参数代入执行计划,直接运行查询或更新操作。
(2)如果相同的 SQL 模板再次执行(仅参数不同),数据库可复用缓存的执行计划,减少编译开销。

2.1.2 即时QL执行过程

${}是即时SQL

第一步:SQL 语句拼接

SELECT * FROM user ORDER BY ${columnName}//如果 columnName = "age"//生成
SELECT * FROM user ORDER BY age; DROP TABLE user;

第二步:SQL 发送到数据库
客户端将拼接好的完整 SQL 字符串通过 Statement 或类似接口发送到数据库

Statement stmt = connection.createStatement();
ResultSet rs = stmt.executeQuery(sql);

第三步:SQL解析与编译
语法解析:检查 SQL 语句的语法是否正确。
语义分析:验证表名、列名等是否存在,权限是否足够。
优化:生成执行计划,选择最优的查询路径。

第四步:SQL执行
数据库根据生成的执行计划执行 SQL,完成查询或更新操作。

2.2性能比较

预编译SQL(#{})性能更高:
绝⼤多数情况下, 某⼀条 SQL 语句可能会被反复调⽤执⾏, 或者每次执⾏的时候只有个别的值不同(⽐如 select 的 where ⼦句值不同, update 的 set ⼦句值不同, insert 的 values 值不同). 如果每次都需要经过上⾯的语法解析, SQL优化、SQL编译等,则效率就明显不⾏了
在这里插入图片描述
预编译SQL,编译⼀次之后会将编译后的SQL语句缓存起来,后⾯再次执⾏这条语句时,不会再次编译 (只是输⼊的参数不同), 省去了解析优化等过程, 以此来提⾼效率

预编译SQL(#{})更安全(防⽌SQL注⼊):
由于没有对⽤⼾输⼊进⾏充分检查,⽽SQL⼜是拼接⽽成,在⽤⼾输⼊参数时,在参数中添加⼀些 SQL关键字,达到改变SQL运⾏结果的⽬的,也可以完成恶意攻击。

2.3 排序举例

排序需要用到SQL的关键字ascdesc,把该两个关键字设置为参数时需要用到${},因为#{}会把ascdesc认为是字符串

2.3.1 #{}

Mapper接口:

@Mapper
public interface UserInfoMapper {@Select("select * from userInfo order by username #{flag}")List<UserInfo> findAll(String flag);
}

测试代码

@Slf4j
@SpringBootTest //启动Sring 容器
class UserInfoMapperTest {@Autowiredprivate UserInfoMapper userMapper;@Testvoid findAll() {userMapper.findAll("asc");}
}

运行结果:
在这里插入图片描述

2.3.2 #{}

Mapper接口:

@Mapper
public interface UserInfoMapper {@Select("select * from userInfo order by username ${flag}")List<UserInfo> findAll(String flag);
}

测试代码

@Slf4j
@SpringBootTest //启动Sring 容器
class UserInfoMapperTest {@Autowiredprivate UserInfoMapper userMapper;@Testvoid findAll() {userMapper.findAll("asc");}
}

运行结果:
在这里插入图片描述

2.4 like 查询

2.4.1 #{}

Mapper接口:

@Mapper
public interface UserInfoMapper {@Select("select * from user_info where username like '%#{s}%'")List<UserInfo> queryLike(String s);
}

测试代码:

@Slf4j
@SpringBootTest //启动Sring 容器
class UserInfoMapperTest {@Autowiredprivate UserInfoMapper userMapper;@Testvoid queryLike() {String s = "6";userMapper.queryLike(s);}
}

运行结果:
在这里插入图片描述

把 #{} 改成 可以正确查出来 , 但是 {} 可以正确查出来, 但是 可以正确查出来,但是{}存在SQL注⼊的问题, 所以不能直接使⽤ ${}.解决办法: 使⽤ mysql 的内置函数 concat() 来处理,实现代码如下:

修改后的Mapper接口:

@Mapper
public interface UserInfoMapper {@Select("select * from user_info where username like concat('%',#{s},'%') ")List<UserInfo> queryLike(String s);

运行结果:
在这里插入图片描述

2.4.2 ${}

Mapper接口:

@Mapper
public interface UserInfoMapper {@Select("select * from user_info where username like '%${s}%' ")List<UserInfo> queryLike(String s);
}

测试代码:

@Slf4j
@SpringBootTest //启动Sring 容器
class UserInfoMapperTest {@Autowiredprivate UserInfoMapper userMapper;@Testvoid queryLike() {String s = "6";userMapper.queryLike(s);}
}

运行结果:
在这里插入图片描述

3.什么是SQL注入?

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

举例:
下面定义的接口是由username得到该username的信息

Mapper接口:

@Mapper
public interface UserInfoMapper {// 获取参数中的 username@Select("select * from user_info where username = ${username} ")List<UserInfo> queryByUsername( String username);

可以通过输入' or username='来获取该表中所有人的信息
测试代码:

@Slf4j
@SpringBootTest //启动Sring 容器
class UserInfoMapperTest {@Autowiredprivate UserInfoMapper userMapper;@Testvoid queryByUsername() {userMapper.queryByUsername("lisi");}
}

运行结果:
在这里插入图片描述

可以看出来, 查询的数据越界了接口的定义。所以⽤于查询的字段,尽量使⽤#{}预查询的⽅式

SQL注⼊是⼀种⾮常常⻅的数据库攻击⼿段, SQL注⼊漏洞也是⽹络世界中最普遍的漏洞之⼀。

4.数据库连接池

4.1介绍

数据库连接池负责分配、管理和释放数据库连接,它允许应⽤程序重复使⽤⼀个现有的数据库连接,⽽不是再重新建⽴⼀个.
在这里插入图片描述
没有使⽤数据库连接池的情况: 每次执⾏SQL语句, 要先创建⼀个新的连接对象, 然后执⾏SQL语句, SQL语句执⾏完, 再关闭连接对象释放资源. 这种重复的创建连接, 销毁连接⽐较消耗资源

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

优点:
1.减少了⽹络开销
2.资源重⽤
3.提升了系统的性能

4.26.2使⽤

常⻅的数据库连接池:
•C3P0
•DBCP
•Druid
•Hikari
⽬前⽐较流⾏的是 Hikari, Druid
Hikari : SpringBoot默认使⽤的数据库连接池
在这里插入图片描述

Hikari 是⽇语"光"的意思(ひかり), Hikari也是以追求性能极致为⽬标

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

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

如果SpringBoot版本为2.X, 使⽤druid-spring-boot-starter 依赖

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

Druid连接池是阿⾥巴巴开源的数据库连接池项⽬
功能强⼤,性能优秀,是Java语⾔最好的数据库连接池之⼀

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

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

相关文章

Poco C++全面开发指南:日期和时间

时间戳 时间戳是指格林威治时间1970年01月01日00时00分00秒&#xff08;北京时间1970年01月01日08时00分00秒&#xff09;起至现在的总秒数。在poco中可以可以使用Timestamp类获取。 #include <Poco/Timestamp.h> #include <iostream>int main() {Poco::Timestam…

水利三维可视化平台怎么做?快速上手的3步指南

分享大纲&#xff1a; 1、了解水利三维可视化平台 2、选择合适的开发平台 3、快速搭建水利三维可视化平台 第一步&#xff1a;了解水利三维可视化平台 水利三维可视化平台是利用大数据、物联网、数字孪生等技术&#xff0c;将物理实体数字化建模&#xff0c;并通过三维可视化技…

高级前端面试题:基于2025年最新技术体系

高级前端面试题:基于2025年最新技术体系 引言 随着前端技术的不断发展,2025年的前端面试题也呈现出新的特点和趋势。本报告基于最新的前端技术体系,收集了当前热门的面试题,旨在帮助准备高级前端工程师面试的候选人全面了解面试考察点。报告内容涵盖HTML5 Canvas、WebGL、…

图像处理——边缘检测

1 概述 边缘检测是图像处理和计算机视觉中的一项基本技术&#xff0c;用于识别图像中亮度变化剧烈的像素点&#xff0c;这些像素点通常对应于物体的边界。它通过检测图像中亮度或颜色变化显著的区域&#xff0c;提取出物体的轮廓&#xff0c;常用于计算机视觉、图像处理和模式识…

c语言的常用的预处理指令和条件编译

c语言的常用的预处理指令和条件编译 预处理详解预定义符号#define#define 定义标识符#define 定义宏带副作用的宏参数宏和函数的对比#define命名约定和#undef移除宏 # 和 ## 参数插入字符串字符串的自动连接#宏参数 命令行定义条件编译#if和#endif多分支条件编译#if、#elif、#e…

TTL、RS-232 和 RS-485 串行通信电平标准区别解析

TTL、RS-232 和 RS-485 是三种常见的串行通信电平标准&#xff0c;它们各自有不同的协议特点&#xff0c;适用于不同的应用场景。以下是它们的主要特点对比&#xff1a; ​​1. TTL&#xff08;Transistor-Transistor Logic&#xff09;​​ ​​主要特点​​ ​​单端信号​…

SwinTransformer改进(6):与Dual Cross-Attention结合的视觉模型

在计算机视觉领域,Transformer架构正逐渐取代传统的CNN成为主流。 本文将深入解析一个结合了Swin Transformer和Dual Cross-Attention(DCA)的创新模型实现。 模型概述 这个实现的核心是将Swin Transformer(一种高效的视觉Transformer)与创新的Dual Cross-Attention模块相结…

Dify框架面试内容整理-Dify框架

什么是Dify框架? Dify框架是一个开源的AI应用开发平台,专注于帮助开发者和非技术人员快速构建、部署和管理基于大语言模型(如GPT系列、国产开源模型)的应用。 Dify框架的特点:

道可云人工智能每日资讯|“人工智能科技体验展”在中国科学技术馆举行

道可云元宇宙每日简报&#xff08;2025年4月28日&#xff09;讯&#xff0c;今日元宇宙新鲜事有&#xff1a; 《2025年提升全民数字素养与技能工作要点》发布 近日&#xff0c;中央网信办、教育部、工业和信息化部、人力资源社会保障部联合印发《2025年提升全民数字素养与技能…

基于javaweb的SpringBoot新闻发布系统设计与实现(源码+文档+部署讲解)

技术范围&#xff1a;SpringBoot、Vue、SSM、HLMT、Jsp、PHP、Nodejs、Python、爬虫、数据可视化、小程序、安卓app、大数据、物联网、机器学习等设计与开发。 主要内容&#xff1a;免费功能设计、开题报告、任务书、中期检查PPT、系统功能实现、代码编写、论文编写和辅导、论文…

苍穹外卖心得体会

1 登录认证 技术点&#xff1a;JWT令牌技术&#xff08;JSON Web Token&#xff09; JWT&#xff08;JSON Web Token&#xff09;是一种令牌技术&#xff0c;主要由三部分组成&#xff1a;Header头部、Payload载荷和Signature签名。Header头部存储令牌的类型&#xff08;如JW…

车载功能测试-车载域控/BCM控制器测试用例开发流程【用例导出方法+优先级划分原则】

目录 1 摘要2 位置灯手动控制简述2.1 位置灯手动控制需求简述2.2 位置灯手动控制逻辑交互图 3 用例导出方法以及优先级原则3.1 用例导出方法3.1.1 用例导出方法介绍3.1.2 用例导出方法关键差异分析 3.2 优先级规则3.2.1 优先级划分的核心原则3.2.2 具体等级定义与判定标准 3.3 …

Linux系统基础:基础指令简介(网络概念部分)

简介&#xff1a;Linux 是一种开源的类 Unix 操作系统内核&#xff0c;由 Linus Torvalds 于 1991 年首次发布。经过多年发展&#xff0c;它已成为服务器、嵌入式设备和个人计算机领域的重要操作系统。 网络基础概念 初始协议 简单来说&#xff0c;协议是一种约定&#xff0…

多模态(3):实战 GPT-4o 视频理解

最近&#xff0c;OpenAI 团队的 GPT-4o 模型&#xff0c;在多模态方面的能力有了大幅提升&#xff0c;这次我们就使用 GPT-4o 完成一个视频理解的实战。 1. 环境搭建 1.1 安装 FFmpeg 做视频处理&#xff0c;我们需要用到 FFmpeg 这款功能强大的开源多媒体处理工具。FFmpeg…

(27)VTK C++开发示例 ---将点坐标写入 STL文件

文章目录 1. 概述2. CMake链接VTK3. main.cpp文件4. 演示效果 更多精彩内容&#x1f449;内容导航 &#x1f448;&#x1f449;VTK开发 &#x1f448; 1. 概述 此示例使用 vtkSTLWriter 将存储在 vtkPolyData 对象中的 3D 几何数据保存到 STL 文件&#xff0c;并读取stl文件显示…

2. python协程/异步编程详解

目录 1. 简单的异步程序 2. 协程函数和协程对象 3. 事件循环 4. 任务对象Task及Future对象 4.1 Task与Future的关系 4.2 Future对象 4.3 全局对象和循环事件对象 5. await关键字 6. 异步上下文管理 7.异步迭代器 8. asyncio的常用函数 8.1 asyncio.run 8.2 asyncio.get…

智慧园区IOT项目与AI时代下的机遇 - Java架构师面试实战

在互联网大厂的Java求职者面试中&#xff0c;面试官通常会针对实际业务场景提出一系列问题。以下是关于智慧园区IOT项目及AI时代下的机遇的面试模拟对话。 第一轮提问 面试官&#xff1a;马架构&#xff0c;请简要介绍下智慧园区IOT项目的整体架构设计。 马架构&#xff1a;…

论文导读 - 基于特征融合的电子鼻多任务深度学习模型研究

基于特征融合的电子鼻多任务深度学习模型研究 原论文地址&#xff1a;https://www.sciencedirect.com/science/article/pii/S0925400524009365 引用此论文&#xff08;GB/T 7714-2015&#xff09;&#xff1a; NI W, WANG T, WU Y, et al. Multi-task deep learning model f…

AI超级智能体项目教程(二)---后端项目初始化(设计knif4j接口文档的使用)

文章目录 1.选择JDK的版本和相关配置2.添加依赖信息2.1指定lombok版本信息2.2引入hutool工具类2.3了解knif4j依赖2.4引入knif4j依赖 3.contrller测试3.1完成yml文件配置3.2修改默认扫描路径3.3controller具体的内容3.4配置接口和访问路径3.5如何访问3.6调试接口3.6调试接口 1.选…

linux blueZ 第四篇:BLE GATT 编程与自动化——Python 与 C/C++ 实战

本篇聚焦 BLE(Bluetooth Low Energy)GATT 协议层的编程与自动化实践,涵盖 GATT 基础、DBus API 原理、Python(dbus-next/bleak)示例、C/C++ (BlueZ GATT API)示例,以及自动发现、读写特征、订阅通知、安全配对与脚本化测试。 目录 BLE GATT 基础概念 BlueZ DBus GATT 模…