亚洲乱码中文字幕综合,中国熟女仑乱hd,亚洲精品乱拍国产一区二区三区,一本大道卡一卡二卡三乱码全集资源,又粗又黄又硬又爽的免费视频

深入解析SpringBoot中#{}和${}的使用

 更新時(shí)間:2025年04月25日 10:30:22   作者:Code哈哈笑  
本文主要介紹了深入解析SpringBoot中#{}和${}的使用,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧

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

1.1數(shù)據(jù)準(zhǔn)備

1.1.1.MySQL數(shù)據(jù)準(zhǔn)備

(1)創(chuàng)建數(shù)據(jù)庫(kù):

CREATE DATABASE mybatis_study DEFAULT CHARACTER SET utf8mb4;

(2)使用數(shù)據(jù)庫(kù)

-- 使?數(shù)據(jù)數(shù)據(jù)
USE mybatis_study;

(3)創(chuàng)建用戶表

-- 創(chuàng)建表[??表]

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-默認(rèn)',
 `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.創(chuàng)建對(duì)應(yīng)的實(shí)體類(lèi)

實(shí)體類(lèi)的屬性名與表中的字段名??對(duì)應(yīng)

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

}

在這里插入圖片描述

注意:在實(shí)際開(kāi)發(fā)中不管什么實(shí)體類(lèi)都要設(shè)置刪除標(biāo)志、創(chuàng)建時(shí)間、修改時(shí)間

1.2 獲取Integer類(lèi)型

1.2.1 #{}

Mapper接口:

@Mapper
public interface UserInfoMapper {
    // 獲取參數(shù)中的 UserId
    @Select("select * from user_info where id = #{userId} ")
    UserInfo queryById(@Param("userId") Integer id);

測(cè)試代碼:

@Slf4j
@SpringBootTest //啟動(dòng)Sring 容器
class UserInfoMapperTest {

    @Test
    void queryById() {
        UserInfo result = userInfoMapper.queryById(8);
        log.info(result.toString());
    }
}

運(yùn)行結(jié)果:

在這里插入圖片描述

通過(guò)日志可以發(fā)現(xiàn),?進(jìn)行占位,傳的參數(shù)進(jìn)行綁定到占位符。

1.2.2 ${}

Mapper接口:

@Mapper
public interface UserInfoMapper {
    // 獲取參數(shù)中的 UserId
    @Select("select * from user_info where id = ${userId} ")
    UserInfo queryById(@Param("userId") Integer id);

測(cè)試代碼:

@Slf4j
@SpringBootTest //啟動(dòng)Sring 容器
class UserInfoMapperTest {

    @Test
    void queryById() {
        UserInfo result = userInfoMapper.queryById(8);
        log.info(result.toString());
    }
}

運(yùn)行結(jié)果:

在這里插入圖片描述

通過(guò)日志可以發(fā)現(xiàn),SQL命令是完整的,因?yàn)椋摲椒ㄊ前炎址唇釉谝黄饒?zhí)行的。

1.3 獲取String類(lèi)型

1.3.1 #{}

Mapper接口:

@Mapper
public interface UserInfoMapper {
    // 獲取參數(shù)中的 username
    @Select("select * from user_info where username = #{username} ")
    List<UserInfo> queryByUsername( String username);

測(cè)試代碼:

@Slf4j
@SpringBootTest //啟動(dòng)Sring 容器
class UserInfoMapperTest {
    @Autowired
    private UserInfoMapper userMapper;

    @Test
    void queryByUsername() {
        userMapper.queryByUsername("lisi");
    }
}

運(yùn)行結(jié)果:

在這里插入圖片描述

通過(guò)日志可以發(fā)現(xiàn),?進(jìn)行占位,傳的參數(shù)進(jìn)行綁定到占位符。

1.3.2 ${}

Mapper接口:

@Mapper
public interface UserInfoMapper {
    // 獲取參數(shù)中的 username
    @Select("select * from user_info where username = ${username} ")
    List<UserInfo> queryByUsername( String username);

測(cè)試代碼:

@Slf4j
@SpringBootTest //啟動(dòng)Sring 容器
class UserInfoMapperTest {
    @Autowired
    private UserInfoMapper userMapper;

    @Test
    void queryByUsername() {
        userMapper.queryByUsername("lisi");
    }
}

運(yùn)行結(jié)果:報(bào)錯(cuò)

在這里插入圖片描述

在這里插入圖片描述

從SQL語(yǔ)句中明顯的看到WHERE username 后面的字符串沒(méi)有引號(hào),導(dǎo)致報(bào)錯(cuò)。

因?yàn)椋?{}直接把字符內(nèi)容直接放進(jìn)SQL語(yǔ)句中而沒(méi)有加單引號(hào)。

修改后的mapper接口:

@Mapper
public interface UserInfoMapper {
    // 獲取參數(shù)中的 username
    @Select("select * from user_info where username = '${username}' ")
    UserInfo queryByUsername( String username);

在這里插入圖片描述

2.#{} 和 ${}的區(qū)別

2.1 預(yù)編譯SQL和即時(shí)SQL的執(zhí)行過(guò)程

2.1.1 預(yù)編譯SQL執(zhí)行過(guò)程

#{}是預(yù)編譯SQL。

第一步:數(shù)據(jù)庫(kù)客戶端(如 JDBC 驅(qū)動(dòng))將 SQL 模板發(fā)送到數(shù)據(jù)庫(kù)服務(wù)器。

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

第二步:SQL 預(yù)編譯
(1)數(shù)據(jù)庫(kù)解析 SQL 模板,生成執(zhí)行計(jì)劃(包括語(yǔ)法檢查、語(yǔ)義分析、優(yōu)化等),并緩存該計(jì)劃。
(2)此時(shí),占位符 ? 的具體值尚未填充,數(shù)據(jù)庫(kù)只處理 SQL 的結(jié)構(gòu)。

第三步:客戶端通過(guò) PreparedStatement 的方法設(shè)置參數(shù)值

//參數(shù)值以二進(jìn)制形式單獨(dú)發(fā)送到數(shù)據(jù)庫(kù),不會(huì)直接拼接到 SQL 中,避免了 SQL 注入
pstmt.setInt(1, 123);    // 綁定 id
pstmt.setString(2, "Alice"); // 綁定 name

第四步:SQL 執(zhí)行
(1)數(shù)據(jù)庫(kù)使用緩存的執(zhí)行計(jì)劃,將綁定參數(shù)代入執(zhí)行計(jì)劃,直接運(yùn)行查詢或更新操作。
(2)如果相同的 SQL 模板再次執(zhí)行(僅參數(shù)不同),數(shù)據(jù)庫(kù)可復(fù)用緩存的執(zhí)行計(jì)劃,減少編譯開(kāi)銷(xiāo)。

2.1.2 即時(shí)QL執(zhí)行過(guò)程

${}是即時(shí)SQL。

第一步:SQL 語(yǔ)句拼接

SELECT * FROM user ORDER BY ${columnName}

//如果 columnName = "age"

//生成
SELECT * FROM user ORDER BY age; DROP TABLE user;

第二步:SQL 發(fā)送到數(shù)據(jù)庫(kù)
客戶端將拼接好的完整 SQL 字符串通過(guò) Statement 或類(lèi)似接口發(fā)送到數(shù)據(jù)庫(kù)

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

第三步:SQL解析與編譯
語(yǔ)法解析:檢查 SQL 語(yǔ)句的語(yǔ)法是否正確。
語(yǔ)義分析:驗(yàn)證表名、列名等是否存在,權(quán)限是否足夠。
優(yōu)化:生成執(zhí)行計(jì)劃,選擇最優(yōu)的查詢路徑。

第四步:SQL執(zhí)行
數(shù)據(jù)庫(kù)根據(jù)生成的執(zhí)行計(jì)劃執(zhí)行 SQL,完成查詢或更新操作。

2.2性能比較

預(yù)編譯SQL(#{})性能更高:
絕?多數(shù)情況下, 某?條 SQL 語(yǔ)句可能會(huì)被反復(fù)調(diào)?執(zhí)?, 或者每次執(zhí)?的時(shí)候只有個(gè)別的值不同(?如 select 的 where ?句值不同, update 的 set ?句值不同, insert 的 values 值不同). 如果每次都需要經(jīng)過(guò)上?的語(yǔ)法解析, SQL優(yōu)化、SQL編譯等,則效率就明顯不?了

在這里插入圖片描述

預(yù)編譯SQL,編譯?次之后會(huì)將編譯后的SQL語(yǔ)句緩存起來(lái),后?再次執(zhí)?這條語(yǔ)句時(shí),不會(huì)再次編譯 (只是輸?的參數(shù)不同), 省去了解析優(yōu)化等過(guò)程, 以此來(lái)提?效率

預(yù)編譯SQL(#{})更安全(防?SQL注?):
由于沒(méi)有對(duì)??輸?進(jìn)?充分檢查,?SQL?是拼接?成,在??輸?參數(shù)時(shí),在參數(shù)中添加?些 SQL關(guān)鍵字,達(dá)到改變SQL運(yùn)?結(jié)果的?的,也可以完成惡意攻擊。

2.3 排序舉例

排序需要用到SQL的關(guān)鍵字asc 和desc,把該兩個(gè)關(guān)鍵字設(shè)置為參數(shù)時(shí)需要用到${},因?yàn)?code>#{}會(huì)把asc 和desc認(rèn)為是字符串

2.3.1 #{}

Mapper接口:

@Mapper
public interface UserInfoMapper {

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

測(cè)試代碼

@Slf4j
@SpringBootTest //啟動(dòng)Sring 容器
class UserInfoMapperTest {

    @Autowired
    private UserInfoMapper userMapper;

    @Test
    void findAll() {
        userMapper.findAll("asc");
    }
}

運(yùn)行結(jié)果:

在這里插入圖片描述

2.3.2 #{}

Mapper接口:

@Mapper
public interface UserInfoMapper {

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

測(cè)試代碼

@Slf4j
@SpringBootTest //啟動(dòng)Sring 容器
class UserInfoMapperTest {

    @Autowired
    private UserInfoMapper userMapper;

    @Test
    void findAll() {
        userMapper.findAll("asc");
    }
}

運(yùn)行結(jié)果:

在這里插入圖片描述

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

測(cè)試代碼:

@Slf4j
@SpringBootTest //啟動(dòng)Sring 容器
class UserInfoMapperTest {

    @Autowired
    private UserInfoMapper userMapper;

    @Test
    void queryLike() {
        String s = "6";
        userMapper.queryLike(s);
    }
}

運(yùn)行結(jié)果:

在這里插入圖片描述

把 #{} 改成 可以正確查出來(lái) , 但是 {} 可以正確查出來(lái), 但是可以正確查出來(lái),但是{}存在SQL注?的問(wèn)題, 所以不能直接使? ${}.解決辦法: 使? mysql 的內(nèi)置函數(shù) concat() 來(lái)處理,實(shí)現(xiàn)代碼如下:

修改后的Mapper接口:

@Mapper
public interface UserInfoMapper {

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

運(yùn)行結(jié)果:

在這里插入圖片描述

2.4.2 ${}

Mapper接口:

@Mapper
public interface UserInfoMapper {

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

測(cè)試代碼:

@Slf4j
@SpringBootTest //啟動(dòng)Sring 容器
class UserInfoMapperTest {

    @Autowired
    private UserInfoMapper userMapper;

    @Test
    void queryLike() {
        String s = "6";
        userMapper.queryLike(s);
    }
}

運(yùn)行結(jié)果:

在這里插入圖片描述

3.什么是SQL注入?

SQL注?:是通過(guò)操作輸?的數(shù)據(jù)來(lái)修改事先定義好的SQL語(yǔ)句,以達(dá)到執(zhí)?代碼對(duì)服務(wù)器進(jìn)?攻擊的?法。

舉例:
下面定義的接口是由username得到該username的信息

Mapper接口:

@Mapper
public interface UserInfoMapper {
    // 獲取參數(shù)中的 username
    @Select("select * from user_info where username = ${username} ")
    List<UserInfo> queryByUsername( String username);

可以通過(guò)輸入' or username='來(lái)獲取該表中所有人的信息
測(cè)試代碼:

@Slf4j
@SpringBootTest //啟動(dòng)Sring 容器
class UserInfoMapperTest {
    @Autowired
    private UserInfoMapper userMapper;

    @Test
    void queryByUsername() {
        userMapper.queryByUsername("lisi");
    }
}

運(yùn)行結(jié)果:

在這里插入圖片描述

可以看出來(lái), 查詢的數(shù)據(jù)越界了接口的定義。所以?于查詢的字段,盡量使?#{}預(yù)查詢的?式

SQL注?是?種?常常?的數(shù)據(jù)庫(kù)攻擊?段, SQL注?漏洞也是?絡(luò)世界中最普遍的漏洞之?。

4.數(shù)據(jù)庫(kù)連接池

4.1介紹

數(shù)據(jù)庫(kù)連接池負(fù)責(zé)分配、管理和釋放數(shù)據(jù)庫(kù)連接,它允許應(yīng)?程序重復(fù)使??個(gè)現(xiàn)有的數(shù)據(jù)庫(kù)連接,?不是再重新建??個(gè).

在這里插入圖片描述

沒(méi)有使?數(shù)據(jù)庫(kù)連接池的情況: 每次執(zhí)?SQL語(yǔ)句, 要先創(chuàng)建?個(gè)新的連接對(duì)象, 然后執(zhí)?SQL語(yǔ)句, SQL語(yǔ)句執(zhí)?完, 再關(guān)閉連接對(duì)象釋放資源. 這種重復(fù)的創(chuàng)建連接, 銷(xiāo)毀連接?較消耗資源

使?數(shù)據(jù)庫(kù)連接池的情況: 程序啟動(dòng)時(shí), 會(huì)在數(shù)據(jù)庫(kù)連接池中創(chuàng)建?定數(shù)量的Connection對(duì)象, 當(dāng)客?請(qǐng)求數(shù)據(jù)庫(kù)連接池, 會(huì)從數(shù)據(jù)庫(kù)連接池中獲取Connection對(duì)象, 然后執(zhí)?SQL, SQL語(yǔ)句執(zhí)?完, 再把 Connection歸還給連接池.

優(yōu)點(diǎn):
1.減少了?絡(luò)開(kāi)銷(xiāo)
2.資源重?
3.提升了系統(tǒng)的性能

4.2使?

常?的數(shù)據(jù)庫(kù)連接池:

  • C3P0
  • DBCP
  • Druid
  • Hikari

?前?較流?的是 Hikari, Druid
Hikari : SpringBoot默認(rèn)使?的數(shù)據(jù)庫(kù)連接池

在這里插入圖片描述

Hikari 是?語(yǔ)"光"的意思(ひかり), Hikari也是以追求性能極致為?標(biāo)

Druid

如果我們想把默認(rèn)的數(shù)據(jù)庫(kù)連接池切換為Druid數(shù)據(jù)庫(kù)連接池, 只需要引?相關(guān)依賴(lài)即可

<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 依賴(lài)

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

Druid連接池是阿?巴巴開(kāi)源的數(shù)據(jù)庫(kù)連接池項(xiàng)?
功能強(qiáng)?,性能優(yōu)秀,是Java語(yǔ)?最好的數(shù)據(jù)庫(kù)連接池之?

到此這篇關(guān)于深入解析SpringBoot中#{} 和 ${}的使用的文章就介紹到這了,更多相關(guān)SpringBoot中#{} 和 ${}內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • IDEA中如何正確快速打jar包的方式

    IDEA中如何正確快速打jar包的方式

    這篇文章主要介紹了IDEA中如何正確快速打jar包,本文通過(guò)圖文并茂的形式給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2020-06-06
  • springboot后臺(tái)session的存儲(chǔ)與取出方式

    springboot后臺(tái)session的存儲(chǔ)與取出方式

    這篇文章主要介紹了springboot后臺(tái)session的存儲(chǔ)與取出方式,具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2024-06-06
  • java8新特性-Stream入門(mén)學(xué)習(xí)心得

    java8新特性-Stream入門(mén)學(xué)習(xí)心得

    這篇文章主要介紹了java8新特性-Stream入門(mén)學(xué)習(xí)心得,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2023-03-03
  • Java Date類(lèi)常用示例_動(dòng)力節(jié)點(diǎn)Java學(xué)院整理

    Java Date類(lèi)常用示例_動(dòng)力節(jié)點(diǎn)Java學(xué)院整理

    在JDK1.0中,Date類(lèi)是唯一的一個(gè)代表時(shí)間的類(lèi),但是由于Date類(lèi)不便于實(shí)現(xiàn)國(guó)際化,所以從JDK1.1版本開(kāi)始,推薦使用Calendar類(lèi)進(jìn)行時(shí)間和日期處理。這里簡(jiǎn)單介紹一下Date類(lèi)的使用,需要的朋友可以參考下
    2017-05-05
  • SpringMVC @NotNull校驗(yàn)不生效的解決方案

    SpringMVC @NotNull校驗(yàn)不生效的解決方案

    這篇文章主要介紹了SpringMVC @NotNull校驗(yàn)不生效的解決方案,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2021-09-09
  • java實(shí)現(xiàn)把一個(gè)List集合拆分成多個(gè)的操作

    java實(shí)現(xiàn)把一個(gè)List集合拆分成多個(gè)的操作

    這篇文章主要介紹了java實(shí)現(xiàn)把一個(gè)List集合拆分成多個(gè)的操作,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧
    2020-08-08
  • 簡(jiǎn)單了解java集合框架LinkedList使用方法

    簡(jiǎn)單了解java集合框架LinkedList使用方法

    這篇文章主要介紹了簡(jiǎn)單了解java集合框架LinkedList使用方法,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下
    2020-08-08
  • JAVA內(nèi)存模型(JMM)詳解

    JAVA內(nèi)存模型(JMM)詳解

    這篇文章主要介紹了JAVA內(nèi)存模型(JMM)詳解的相關(guān)資料,需要的朋友可以參考下
    2022-12-12
  • Java拖曳鼠標(biāo)實(shí)現(xiàn)畫(huà)線功能的方法

    Java拖曳鼠標(biāo)實(shí)現(xiàn)畫(huà)線功能的方法

    這篇文章主要介紹了Java拖曳鼠標(biāo)實(shí)現(xiàn)畫(huà)線功能的方法,需要的朋友可以參考下
    2014-07-07
  • java靜態(tài)工具類(lèi)注入service出現(xiàn)NullPointerException異常處理

    java靜態(tài)工具類(lèi)注入service出現(xiàn)NullPointerException異常處理

    如果我們要在我們自己封裝的Utils工具類(lèi)中或者非controller普通類(lèi)中使用@Autowired注解注入Service或者M(jìn)apper接口,直接注入是報(bào)錯(cuò)的,因Utils用了靜態(tài)方法,我們無(wú)法直接用非靜態(tài)接口的,遇到這問(wèn)題,我們要想法解決,下面小編就簡(jiǎn)單介紹解決辦法,需要的朋友可參考下
    2021-09-09

最新評(píng)論