告別SQL查詢煩惱!Spring Boot 強(qiáng)大的六種查詢模式
環(huán)境:SpringBoot3.4.2
1. 簡(jiǎn)介
Spring Data JPA作為Spring生態(tài)中簡(jiǎn)化數(shù)據(jù)訪問(wèn)的核心組件,通過(guò)抽象JPA規(guī)范降低了持久層開發(fā)復(fù)雜度。其查詢模式覆蓋從快速原型開發(fā)到復(fù)雜業(yè)務(wù)場(chǎng)景的全生命周期需求:
- 方法名派生查詢適合簡(jiǎn)單條件檢索,如用戶狀態(tài)過(guò)濾
- @Query注解支持原生SQL與JPQL,可處理跨庫(kù)聯(lián)表查詢或數(shù)據(jù)庫(kù)特定優(yōu)化
- JPA Criteria API與Specification接口則通過(guò)動(dòng)態(tài)條件構(gòu)建,滿足那些多維度篩選高靈活性場(chǎng)景
分頁(yè)排序與事務(wù)管理集成進(jìn)一步強(qiáng)化了其在企業(yè)級(jí)應(yīng)用中的實(shí)用性。
本篇文章將為你詳細(xì)介紹6種強(qiáng)大的查詢模式。
2.實(shí)戰(zhàn)案例
2.1 派生查詢(基于方法名)
Spring Data JPA支持通過(guò)方法名定義查詢,遵循命名約定(如findBy、And、Or等)自動(dòng)生成JPQL查詢語(yǔ)句,無(wú)需手動(dòng)編寫SQL,簡(jiǎn)化數(shù)據(jù)訪問(wèn)層開發(fā),提升編碼效率與可讀性,如下示例:
public interface BookRepository extends JpaRepository<Book, Long> {
Optional<Book> findByTitle(String title) ;
List<Book> findByPriceGreaterThan(BigDecimal price);
}? 可讀性強(qiáng)且易于維護(hù)。
?? 不適用于復(fù)雜的聯(lián)接或篩選條件。
?? 專業(yè)提示:對(duì)于簡(jiǎn)單的增刪改查(CRUD)操作或簡(jiǎn)單篩選條件,使用派生查詢。不要在業(yè)務(wù)邏輯中過(guò)度使用它們。
如下列出了支持的查詢方法謂詞關(guān)鍵字和修飾符:
圖片
2.2 JPQL查詢
JPQL(Java Persistence Query Language)是JPA的查詢語(yǔ)言,基于實(shí)體類及其屬性進(jìn)行面向?qū)ο蟛樵?,支持SELECT、UPDATE、DELETE操作,通過(guò)@Query注解或EntityManager執(zhí)行,屏蔽底層數(shù)據(jù)庫(kù)差異,提升可移植性,如下示例:
@Query("SELECT u FROM Book u WHERE u.price > :status AND u.title LIKE %:keyword%")
List<Book> findBooks(@Param("price") BigDecimal price,
@Param("keyword") String keyword);? 可在不同數(shù)據(jù)庫(kù)間通用。
?? 不支持?jǐn)?shù)據(jù)庫(kù)特有的函數(shù)(如 LIMIT、ILIKE 等)。
?? 專業(yè)提示:當(dāng)需要不使用原生 SQL 而實(shí)現(xiàn)動(dòng)態(tài)篩選或?qū)嶓w關(guān)系時(shí),請(qǐng)使用 JPQL(Java 持久化查詢語(yǔ)言)。
2.3 原生SQL查詢
當(dāng)JPQL無(wú)法滿足復(fù)雜查詢需求(如多表連接、子查詢、數(shù)據(jù)庫(kù)特有函數(shù)或性能優(yōu)化)時(shí),需使用原生SQL。它直接操作數(shù)據(jù)庫(kù),支持高級(jí)特性與特定語(yǔ)法,適用于復(fù)雜報(bào)表、分頁(yè)查詢或遺留系統(tǒng)集成,提升靈活性與性能,如下示例:
@Query(value = """
SELECT b.title, b.isbn, AVG(b.price) as avg_price, COUNT(*) as book_count
FROM t_book b
WHERE b.description LIKE %?1%
AND b.page >= ?2
GROUP BY b.title, b.isbn
HAVING AVG(b.price) > ?3
ORDER BY avg_price DESC
""", nativeQuery = true)
List<Object[]> findBookSummaryByDescriptionAndPage(String desc, Integer page, BigDecimal minAvgPrice);? 非常適合復(fù)雜的聯(lián)接、子查詢或性能調(diào)優(yōu)。
?? 受限于特定的數(shù)據(jù)庫(kù)方言。
?? 專業(yè)提示:將原生查詢封裝在存儲(chǔ)庫(kù)方法中,以保持服務(wù)層的整潔和可移植性。
2.4 Criteria API查詢(動(dòng)態(tài)查詢)
Criteria API 是 JPA 提供的類型安全、面向?qū)ο蟮膭?dòng)態(tài)查詢構(gòu)建方式,通過(guò) Java 代碼而非字符串拼接 JPQL,適用于條件動(dòng)態(tài)變化的查詢場(chǎng)景,提升可維護(hù)性與編譯時(shí)檢查能力,如下示例:
private final EntityManager entityManager ;
public List<Book> findBooksByCriteria(String title, BigDecimal minPrice, Integer minPage, String rating) {
CriteriaBuilder cb = entityManager.getCriteriaBuilder();
CriteriaQuery<Book> query = cb.createQuery(Book.class);
Root<Book> root = query.from(Book.class);
List<Predicate> predicates = new ArrayList<>();
if (title != null && !title.isEmpty()) {
predicates.add(cb.like(cb.lower(root.get("title")), "%" + title.toLowerCase() + "%"));
}
if (minPrice != null) {
predicates.add(cb.greaterThanOrEqualTo(root.get("price"), minPrice));
}
if (minPage != null) {
predicates.add(cb.greaterThanOrEqualTo(root.get("page"), minPage));
}
if (rating != null && !rating.isEmpty()) {
predicates.add(cb.equal(root.get("rating"), rating));
}
query.select(root).where(predicates.toArray(new Predicate[0])).orderBy(cb.asc(root.get("title")));
return entityManager.createQuery(query).getResultList();
}控制臺(tái)輸出:
圖片
? 動(dòng)態(tài)查詢,無(wú)需字符串拼接。
?? 語(yǔ)法冗長(zhǎng)——但安全且功能強(qiáng)大。
?? 專業(yè)提示:在篩選條件經(jīng)常變化的內(nèi)部搜索API中使用CriteriaBuilder。
2.5 Specification API(簡(jiǎn)潔的動(dòng)態(tài)查詢)
Specification 是 Spring Data JPA 對(duì) JPA Criteria API 的封裝,支持以函數(shù)式編程方式構(gòu)建可復(fù)用、可組合的查詢條件。通過(guò) Specification<T> 接口實(shí)現(xiàn)動(dòng)態(tài)查詢,適用于復(fù)雜、多條件組合的業(yè)務(wù)場(chǎng)景,提升代碼可讀性與模塊化程度,尤其適合后臺(tái)管理搜索功能,如下示例:
public class BookSpecs {
public static Specification<Book> hasTitleLike(String keyword) {
return (root, query, criteriaBuilder) -> keyword == null || keyword.isEmpty() ? null
: criteriaBuilder.like(criteriaBuilder.lower(root.get("title")), "%" + keyword.toLowerCase() + "%");
}
public static Specification<Book> hasMinPrice(BigDecimal minPrice) {
return (root, query, criteriaBuilder) -> minPrice == null ? null
: criteriaBuilder.greaterThanOrEqualTo(root.get("price"), minPrice);
}
}Repository需要繼承如下接口
public interface BookRepository
extends JpaSpecificationExecutor<Book> {
}測(cè)試用例
@Test
public void testSpec() {
List<Book> books = this.bookRepository.findAll(BookSpecs.hasTitleLike("Spring")) ;
System.err.println(books) ;
}控制臺(tái)輸出
圖片
JpaSpecificationExecutor支持如下的接口

2.6 QBE查詢
Query by Example(QBE,示例查詢)是一種用戶友好的查詢技術(shù),提供簡(jiǎn)潔的接口,支持動(dòng)態(tài)生成查詢條件。它無(wú)需手動(dòng)編寫包含字段名的查詢語(yǔ)句,甚至完全不需要使用數(shù)據(jù)庫(kù)特定的查詢語(yǔ)言(如 SQL、JPQL),如下示例:
public List<Book> searchBooks(String title, BigDecimal price, String rating) {
// 1.創(chuàng)建示例實(shí)體(Probe)
Book probe = new Book();
probe.setTitle(title);
probe.setPrice(price);
probe.setRating(rating);
// 2.構(gòu)建匹配器(Matcher),實(shí)現(xiàn)復(fù)雜控制
ExampleMatcher matcher = ExampleMatcher.matching()
.withStringMatcher(StringMatcher.CONTAINING) // 字符串使用LIKE %...%
.withIgnoreNullValues() // 忽略null值(默認(rèn))
.withMatcher("rating", match -> match.exact()); // rating字段要求精確匹配
// 3.創(chuàng)建Example實(shí)例
Example<Book> example = Example.of(probe, matcher);
// 4.執(zhí)行查詢
return bookRepository.findAll(example);
}控制臺(tái)輸出
圖片
? 非常適合搜索表單。
?? 不支持聯(lián)表查詢或復(fù)雜邏輯。
?? 專業(yè)提示:可在管理后臺(tái)或管理工具中用于快速篩選。
總結(jié)
圖片






























