Published on

「Spring Boot API 開發:從 0 到 1」Day 22 JPA JPQL 與原生 SQL

在 Spring Data JPA 的世界裡,JPQL(Java Persistence Query Language)是一個強大的工具

它讓我們能夠用類似 SQL 的語法來查詢 Java 物件

今天,我們就來深入了解 JPQL,並看看如何在我們的專案中運用它

JPQL 簡介

JPQL 是一種物件導向的查詢語言,專為 JPA 設計,用於查詢 JPA 管理的 實體

它的語法類似 SQL,但操作的是 Java 類別和屬性,而不是資料庫的表格和欄位

相關規則

  • 使用實體類別名稱和屬性名稱,而不是資料庫的表格名稱和欄位名稱
  • 除了關鍵字外,它的查詢語法對大小寫敏感
  • 支持多種查詢類型,包括 SELECT、UPDATE 和 DELETE 等
  • 提供豐富的函式和運算符,如 CONCAT、LENGTH、BETWEEN 等
  • 支持參數綁定,提高安全性和可重用性

與 SQL 的區別

  • JPQL 操作的是 Java 物件(類別),SQL 操作的是資料庫表格
  • JPQL 是與資料庫無關的,SQL 則依賴於特定的資料庫系統
  • JPQL 的 JOIN 語法簡化,和 SQL 的 JOIN 語法略有不同
  • JPQL 提供了一些物件導向的特性,如多態查詢

修改程式碼

讓我們修改上個範例的 TodoRepository,把原本用查詢方法(Query Methods)實作的地方,改用 JPQL 來改寫

使用 @Query 註解來標示相關的 JPQL

使用 @Param 註解來將方法參數與 JPQL 查詢中的參數綁定

public interface TodoRepository extends JpaRepository<Todo, Long> {

    @Query("SELECT t FROM Todo t WHERE t.title = :title")
    List<Todo> findByTitle(@Param("title") String title);

    @Query("SELECT t FROM Todo t WHERE t.completed = true")
    List<Todo> findByCompletedTrue();

    @Query("SELECT t FROM Todo t WHERE t.title LIKE %:keyword% ORDER BY t.id DESC")
    List<Todo> findByTitleContainingOrderByIdDesc(@Param("keyword") String keyword);

    @Query("SELECT COUNT(t) FROM Todo t WHERE t.completed = false")
    long countByCompletedFalse();
}

讓我們來解說每個 JPQL 查詢

  • findByTitle: 這個查詢選擇所有和查詢的 title 完全一致的 Todo 項目
  • findByCompletedTrue: 選擇所有已完成的 Todo 項目
  • findByTitleContainingOrderByIdDesc: 這個查詢使用 LIKE 關鍵字進行 title 模糊查詢,並按 id 降序排序結果
    • 注意,這裡的查詢區分大小寫,如果要不區分大小寫的話,可以使用 LOWER
  • countByCompletedFalse: 計算所有未完成的 Todo 項目數量

因為是修改原有的查詢方法(Query Methods),所以 Controller 不用修改

測試

一樣可以使用之前的 api-test.http 來測試

原生 SQL

我們可以使用 @Query 註解並設定 nativeQuery = true,就可以指定使用原生 SQL

@Query(value = "SELECT * FROM todos WHERE title = ?1", nativeQuery = true)
List<Todo> findByTitleNative(String title);

JPQL 的優缺點

優點

  • 可移植性:JPQL 查詢可以在不同的資料庫之間移植,無需修改
  • 物件導向:直接操作實體對象,與程式碼更加一致
  • 類型安全:可以在編譯時期檢查語法錯誤
  • 簡化複雜查詢:相比查詢方法,可以處理更複雜的查詢邏輯
  • 靈活性:支持動態查詢和複雜的條件組合

缺點

  • 學習成本:需要學習新的查詢語言語法
  • 功能限制:某些資料庫特定的功能 (SQL) 可能無法在 JPQL 使用
  • 複雜查詢的局限性:對於極其複雜的查詢,可能還是需要使用原生 SQL
  • 除錯困難:錯誤信息可能不如原生 SQL 清晰
  • 效能問題:在某些情況下,手動優化的 SQL 可能比 JPQL 產生的查詢更高效

最佳實務

  • 適度使用:對於簡單查詢,查詢方法 可能更直觀;複雜查詢則考慮使用 JPQL
  • 參數綁定:始終使用參數綁定 來防止 SQL Injection
  • 測試驗證:編寫測試 確保 JPQL 查詢的正確性
  • 效能監控:對於關鍵查詢,監控並分析產生的 SQL 以確保效能
  • 結合使用:某些情況下,可以考慮結合使用 JPQL 和原生 SQL 以達到最佳效果

結論

JPQL 是 Spring Data JPA 中一個強大的查詢工具,它彌補了查詢方法的一些限制,同時保持了與 Java 程式碼的一致性

通過合理使用 JPQL,我們可以編寫更靈活、更複雜的查詢,同時保持程式碼的可讀性和可維護性

然而,在使用 JPQL 時,我們也需要權衡其優缺點,並在適當的場景下選擇使用

無論是 JPQL、查詢方法還是原生 SQL,選擇正確的工具來完成任務才是最重要的

同步刊登於 iTHome 鐵人賽 「Spring Boot API 開發:從 0 到 1」Day 22 JPQL 查詢

圖片來源:AI 產生

參考連結