【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.pswp.cn/news/903515.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/903515.shtml
英文地址,請注明出處:http://en.pswp.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 模…