MyBatis實(shí)現(xiàn)動(dòng)態(tài)SQL模糊查詢(xún)的示例代碼
在數(shù)據(jù)庫(kù)查詢(xún)中,模糊查詢(xún)是最常用的功能之一。然而,當(dāng)查詢(xún)條件變得復(fù)雜多變時(shí),靜態(tài)SQL往往顯得力不從心。今天我們來(lái)探討如何通過(guò)動(dòng)態(tài)SQL實(shí)現(xiàn)靈活、安全的模糊查詢(xún)。
一、為什么需要?jiǎng)討B(tài)SQL模糊查詢(xún)
1.1 傳統(tǒng)模糊查詢(xún)的局限性
-- 靜態(tài)SQL示例 SELECT * FROM users WHERE username LIKE '%張%' AND email LIKE '%example.com%';
這種寫(xiě)法的問(wèn)題在于:
- 當(dāng)某個(gè)條件為空時(shí),查詢(xún)會(huì)失效
- 條件組合多變時(shí),需要寫(xiě)大量重復(fù)代碼
- 難以應(yīng)對(duì)復(fù)雜的業(yè)務(wù)邏輯
1.2 動(dòng)態(tài)SQL的優(yōu)勢(shì)
- 靈活性:根據(jù)實(shí)際參數(shù)動(dòng)態(tài)生成SQL
- 可維護(hù)性:代碼更簡(jiǎn)潔,易于維護(hù)
- 性能優(yōu)化:避免不必要的查詢(xún)條件
二、MyBatis動(dòng)態(tài)SQL實(shí)現(xiàn)模糊查詢(xún)
2.1 基礎(chǔ)示例:?jiǎn)螚l件模糊查詢(xún)
<!-- MyBatis Mapper XML -->
<select id="searchUsers" resultType="User">
SELECT * FROM users
<where>
<if test="keyword != null and keyword != ''">
AND (username LIKE CONCAT('%', #{keyword}, '%')
OR email LIKE CONCAT('%', #{keyword}, '%')
OR phone LIKE CONCAT('%', #{keyword}, '%'))
</if>
</where>
</select>2.2 多條件組合模糊查詢(xún)
<select id="advancedSearch" resultType="User">
SELECT * FROM users
<where>
<!-- 姓名模糊查詢(xún) -->
<if test="name != null and name != ''">
AND username LIKE CONCAT('%', #{name}, '%')
</if>
<!-- 郵箱模糊查詢(xún) -->
<if test="email != null and email != ''">
AND email LIKE CONCAT('%', #{email}, '%')
</if>
<!-- 電話號(hào)碼模糊查詢(xún)(支持中間四位*號(hào)) -->
<if test="phonePattern != null and phonePattern != ''">
AND phone LIKE REPLACE(#{phonePattern}, '*', '%')
</if>
<!-- 地址多字段模糊查詢(xún) -->
<if test="address != null and address != ''">
AND (
province LIKE CONCAT('%', #{address}, '%')
OR city LIKE CONCAT('%', #{address}, '%')
OR detail LIKE CONCAT('%', #{address}, '%')
)
</if>
</where>
ORDER BY create_time DESC
</select>2.3 使用<choose>實(shí)現(xiàn)條件選擇
<select id="smartSearch" resultType="User">
SELECT * FROM users
<where>
<choose>
<when test="searchType == 'name' and keyword != null">
AND username LIKE CONCAT('%', #{keyword}, '%')
</when>
<when test="searchType == 'email' and keyword != null">
AND email LIKE CONCAT('%', #{keyword}, '%')
</when>
<when test="searchType == 'phone' and keyword != null">
AND phone LIKE CONCAT('%', #{keyword}, '%')
</when>
<otherwise>
AND status = 'ACTIVE'
</otherwise>
</choose>
</where>
</select>三、Java代碼中的動(dòng)態(tài)構(gòu)建
3.1 使用StringBuilder動(dòng)態(tài)構(gòu)建SQL
// 服務(wù)層代碼示例
public List<User> dynamicSearch(UserSearchCriteria criteria) {
StringBuilder sql = new StringBuilder("SELECT * FROM users WHERE 1=1");
List<Object> params = new ArrayList<>();
// 姓名模糊查詢(xún)
if (StringUtils.isNotBlank(criteria.getName())) {
sql.append(" AND username LIKE ?");
params.add("%" + criteria.getName() + "%");
}
// 郵箱模糊查詢(xún)
if (StringUtils.isNotBlank(criteria.getEmail())) {
sql.append(" AND email LIKE ?");
params.add("%" + criteria.getEmail() + "%");
}
// 分頁(yè)處理
if (criteria.getPageSize() > 0) {
sql.append(" LIMIT ?, ?");
params.add(criteria.getOffset());
params.add(criteria.getPageSize());
}
return jdbcTemplate.query(sql.toString(), params.toArray(),
new BeanPropertyRowMapper<>(User.class));
}3.2 使用JPA Specification實(shí)現(xiàn)(Spring Data JPA)
// 使用Specification構(gòu)建動(dòng)態(tài)查詢(xún)
public class UserSpecifications {
public static Specification<User> nameContains(String name) {
return (root, query, cb) ->
StringUtils.isBlank(name) ?
cb.conjunction() :
cb.like(root.get("username"), "%" + name + "%");
}
public static Specification<User> emailContains(String email) {
return (root, query, cb) ->
StringUtils.isBlank(email) ?
cb.conjunction() :
cb.like(root.get("email"), "%" + email + "%");
}
public static Specification<User> multiFieldSearch(String keyword) {
return (root, query, cb) -> {
if (StringUtils.isBlank(keyword)) {
return cb.conjunction();
}
String pattern = "%" + keyword + "%";
return cb.or(
cb.like(root.get("username"), pattern),
cb.like(root.get("email"), pattern),
cb.like(root.get("phone"), pattern)
);
};
}
}
// 使用示例
public List<User> searchUsers(String name, String email) {
return userRepository.findAll(
Specification.where(UserSpecifications.nameContains(name))
.and(UserSpecifications.emailContains(email))
);
}四、高級(jí)技巧與優(yōu)化
4.1 防止SQL注入
// 使用預(yù)編譯語(yǔ)句,永遠(yuǎn)不要直接拼接用戶輸入
String safePattern = "%" + escapeSql(keyword) + "%";
// MyBatis自動(dòng)處理參數(shù),防止SQL注入
<if test="keyword != null">
AND username LIKE CONCAT('%', #{keyword}, '%')
</if>4.2 性能優(yōu)化建議
-- 為經(jīng)常查詢(xún)的字段創(chuàng)建索引 CREATE INDEX idx_username ON users(username); CREATE INDEX idx_email ON users(email); -- 避免前導(dǎo)通配符導(dǎo)致索引失效的情況 -- 不推薦:LIKE '%keyword%' -- 推薦:LIKE 'keyword%'(如果業(yè)務(wù)允許)
4.3 使用全文索引提升模糊查詢(xún)性能
-- MySQL全文索引示例
ALTER TABLE users ADD FULLTEXT INDEX ft_search (username, email);
-- 使用全文索引進(jìn)行模糊查詢(xún)
SELECT * FROM users
WHERE MATCH(username, email) AGAINST('+張* +example*' IN BOOLEAN MODE);五、實(shí)際應(yīng)用場(chǎng)景
5.1 電商商品搜索
<select id="searchProducts" resultType="Product">
SELECT * FROM products
<where>
<if test="productName != null">
AND product_name LIKE CONCAT('%', #{productName}, '%')
</if>
<if test="categoryId != null">
AND category_id = #{categoryId}
</if>
<if test="minPrice != null">
AND price >= #{minPrice}
</if>
<if test="maxPrice != null">
AND price <= #{maxPrice}
</if>
<!-- 模糊搜索商品描述 -->
<if test="keyword != null">
AND (
product_name LIKE CONCAT('%', #{keyword}, '%')
OR description LIKE CONCAT('%', #{keyword}, '%')
OR tags LIKE CONCAT('%', #{keyword}, '%')
)
</if>
</where>
ORDER BY
<choose>
<when test="sortBy == 'price'">price ${sortOrder}</when>
<when test="sortBy == 'sales'">sales_count DESC</when>
<otherwise>create_time DESC</otherwise>
</choose>
</select>5.2 日志查詢(xún)系統(tǒng)
public List<Log> searchLogs(LogQuery query) {
StringBuilder sql = new StringBuilder(
"SELECT * FROM system_logs WHERE 1=1");
// 模糊匹配操作內(nèi)容
if (StringUtils.isNotBlank(query.getContent())) {
sql.append(" AND content LIKE ?");
params.add("%" + query.getContent() + "%");
}
// 模糊匹配用戶IP
if (StringUtils.isNotBlank(query.getIp())) {
sql.append(" AND ip_address LIKE ?");
params.add(query.getIp() + "%"); // IP前綴匹配
}
// 時(shí)間范圍查詢(xún)
if (query.getStartTime() != null) {
sql.append(" AND create_time >= ?");
params.add(query.getStartTime());
}
return jdbcTemplate.query(sql.toString(),
params.toArray(),
new BeanPropertyRowMapper<>(Log.class));
}六、最佳實(shí)踐總結(jié)
安全性第一:始終使用參數(shù)化查詢(xún),防止SQL注入
性能優(yōu)化:為頻繁查詢(xún)的字段建立索引,考慮使用全文搜索
代碼可讀性:保持SQL語(yǔ)句的清晰和可維護(hù)性
適度使用:避免過(guò)度復(fù)雜的動(dòng)態(tài)SQL,必要時(shí)拆分查詢(xún)
測(cè)試覆蓋:確保各種條件組合都能正確工作
結(jié)語(yǔ)
動(dòng)態(tài)SQL模糊查詢(xún)是現(xiàn)代應(yīng)用開(kāi)發(fā)中不可或缺的技能。通過(guò)合理運(yùn)用MyBatis動(dòng)態(tài)標(biāo)簽、JPA Specification或自定義SQL構(gòu)建,我們可以在保證安全性的同時(shí),實(shí)現(xiàn)靈活高效的查詢(xún)功能。記住,好的查詢(xún)?cè)O(shè)計(jì)不僅能讓程序跑得更快,也能讓代碼更易于維護(hù)和擴(kuò)展。
到此這篇關(guān)于MyBatis實(shí)現(xiàn)動(dòng)態(tài)SQL模糊查詢(xún)的示例代碼的文章就介紹到這了,更多相關(guān)MyBatis SQL模糊查詢(xún)內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
Java調(diào)用Redis集群代碼及問(wèn)題解決
這篇文章主要介紹了Java調(diào)用Redis集群代碼及問(wèn)題解決,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下2019-08-08
阿里開(kāi)源Java診斷工具神器使用及場(chǎng)景詳解
這篇文章主要為大家介紹了阿里開(kāi)源Java診斷工具神器使用及場(chǎng)景詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2023-01-01
Java之獲取客戶端真實(shí)IP地址的實(shí)現(xiàn)
在開(kāi)發(fā)工作中,我們常常需要獲取客戶端的IP,本文主要介紹了Jav之獲取客戶端真實(shí)IP地址的實(shí)現(xiàn),具有一定的參考價(jià)值,感興趣的可以了解一下2023-12-12
在SpringBoot中使用P6Spy攔截SQL語(yǔ)句的完整指南
P6Spy 是一個(gè)用于攔截和記錄應(yīng)用程序和數(shù)據(jù)庫(kù)之間的所有 JDBC 操作的開(kāi)源 Java 庫(kù),本文先簡(jiǎn)單介紹一下 P6Spy 的工作原理,然后以在 Spring Boot 中使用 P6Spy 攔截 SQL 語(yǔ)句為例來(lái)演示 P6Spy 的基本功能和使用方式,需要的朋友可以參考下2025-11-11
Windows同時(shí)配置兩個(gè)jdk環(huán)境變量的操作步驟
Java Development Kit (JDK) 是開(kāi)發(fā)Java應(yīng)用程序的基礎(chǔ),包含了編譯器、調(diào)試器以及其他必要的工具,本指南將一步步指導(dǎo)您完成在Windows操作系統(tǒng)上同時(shí)配置兩個(gè)jdk環(huán)境變量的操作步驟,需要的朋友可以參考下2024-09-09
java同步開(kāi)篇入門(mén)簡(jiǎn)單介紹
java中的CountDownLatch、Semaphore、CyclicBarrier這些類(lèi)又不屬于鎖,它們和鎖又有很多共同點(diǎn),都是為了協(xié)同多線程的執(zhí)行,都是一種同步器,所以這里就借用同步來(lái)取名字了,也就是“同步系列”的來(lái)源。下面小編來(lái)簡(jiǎn)單介紹下2019-05-05
SpringBoot生成License的實(shí)現(xiàn)示例
License指的是版權(quán)許可證,那么對(duì)于SpringBoot項(xiàng)目,如何增加License呢?本文就來(lái)介紹一下,感興趣的可以了解一下2021-06-06
深入解析Spring Cloud內(nèi)置的Zuul過(guò)濾器
這篇文章主要給大家深入的介紹了Spring Cloud內(nèi)置的Zuul過(guò)濾器的相關(guān)資料,文中給大家介紹的很詳細(xì),相信對(duì)大家具有一定的參考價(jià)值,需要的朋友們下面來(lái)一起看看吧。2017-02-02

