認識 JPA 的接口
- 1.JPA 接口 JpaRepository
- 2.分頁排序接口 PagingAndSortingRepository
- 3.數據操作接口 CrudRepository
- 4.分頁接口 Pageable 和 Page
- 5.排序類 Sort
JPA 提供了操作數據庫的接口。在開發過程中繼承和使用這些接口,可簡化現有的持久化開發工作。可以使 Spring 找到自定義接口,并生成代理類,后續可以把自定義接口注入 Spring 容器中進行管理。在自定義接口過程中,可以不寫相關的SQL操作,由代理類自動生成。
此前,在《分層開發 Web 應用程序》這篇博文中,已經講述了 Repository 的概念,在此和大家一起回顧一下。
在 Spring 中有 Repository 的概念,Repository 原意指的是 倉庫,即 數據倉庫 的意思。Repository 居于 業務層 和 數據層 之間,將兩者隔離開來,在它的內部封裝了數據查詢和存儲的邏輯。這樣設計的好處有兩個:
- 降低層級之間的耦合:更換、升級 ORM 引擎(Hibernate)并不會影響業務邏輯。
- 提高測試效率:如果在測試時能用 Mock 數據對象代替實際的數據庫操作,運行速度會快很多。
DAO 是傳統 MVC 中 Model 的關鍵角色,全稱是 Data Access Object
。DAO 直接負責數據庫的存取工作,乍一看兩者非常類似,但從架構設計上講兩者有著本質的區別。
Repository 蘊含著真正的 OO 概念,即一個數據倉庫角色,負責所有對象的持久化管理。DAO 則沒有擺脫數據的影子,仍然停留在數據操作的層面上。Repository 是相對對象而言,DAO 則是相對數據庫而言,雖然可能是同一個東西 ,但側重點完全不同。
在 Spring 和 Spring Data JPA 中,有三種 Repository 接口方便開發者直接操作數據倉庫。它們之間的關系如下:
1.JPA 接口 JpaRepository
JpaRepository 繼承自 PagingAndSortingRepository。該接口提供了 JPA 的相關實用功能, 以及通過 Example 進行查詢的功能。Example 對象是 JPA 提供用來構造查詢條件的對象。該接口的關鍵代碼如下:
public interface JpaRepository<T, ID> extends PagingAndSortingRepository<T, ID>, QueryByExampleExecutor<T> {}
在上述代碼中,T 表示 實體對象,ID 表示 主鍵。ID 必須實現序列化。
JpaRepository 提供的方法如下表所示。
| |
---|---|
List<T> findAll(); | 查找所有實體 |
List<T> findAll(Sort var1); | 排序、查找所有實體 |
List<T> findAllById(Iterable<ID> var1); | 返回制定一組 ID 的實體 |
<S extends T> List<S> saveAll(Iterable<S> var1); | 保存集合 |
void flush(); | 執行緩存與數據庫同步 |
<S extends T> S saveAndFlush(S var1); | 強制執行持久化 |
void deleteInBatch(Iterable<T> var1); | 刪除一個實體集合 |
void deleteAllInBatch(); | 刪除所有實體 |
T getOne(ID var1); | 返回 ID 對應的實體。如果不存在,則返回空值 |
<S extends T> List<S> findAll(Example<S> var1); | 查詢滿足 Example 的所有對象 |
<S extends T> List<S> findAll(Example<S> var1, Sort var2); | 查詢滿足 Example 的所有對象,并且進行排序返回 |
2.分頁排序接口 PagingAndSortingRepository
PagingAndSortingRepository 繼承自 CrudRepository 提供的分頁和排序方法。其關鍵代碼如下:
@NoRepositoryBean
public interface PagingAndSortingRepository<T, ID> extends CrudRepository<T, ID> { Iterable<T> findAll(Sort var1);Page<T> findAll(Pageable var1);
}
其方法有如下兩種
Iterable<T> findAII(Sort sort)
:排序功能。它按照sort
制定的排序返回數據。Page<T> findAll(Pageable pageable)
:分頁查詢(含排序功能)。
3.數據操作接口 CrudRepository
CrudRepository 接口繼承自 Repository 接口,并新增了增加、刪除、修改和查詢方法。 CrudRepository 提供的方法見下表:
| |
---|---|
<S extends T> S save(S entity) | 保存實體。當實體中包含主鍵時,JPA 會進行更新操作 |
<S extends T> Iterable<S> saveAll(Iterable<S> entities) | 保存所有實體。實體必須不為空 |
Optional<T> findById(ID id) | 根據主鍵 id 檢索實體 |
boolean existsById(ID id) | 根據主鍵 id 檢索實體,返回是否存在。值為布爾類型 |
Iterable<T> findAll() | 返回所有實體 |
Iterable<T> findAllById(Iterable<ID> ids) | 根據給定的一組 id 值返回一組實體 |
long count() | 返回實體的數量 |
void deleteById(ID id) | 根據 id 刪除數據 |
void delete(T entity) | 刪除給定的實體 |
void deleteAll(Iterable<? extends T> entities) | 刪除實體 |
void deleteAll() | 刪除所有實體 |
4.分頁接口 Pageable 和 Page
Pageable 接口用于構造翻頁查詢,返回 Page 對象。Page 從 0 0 0 開始分頁。
例如,可以通過以下代碼來構建文章的翻頁查詢參數。
@RequestMapping("/article")
public ModelAndView articleList(@RequestParam(value = "start", defaultvalue = "0") Integer start, @RequestParam(value = "limit", defaultvalue = "10") Integer limit) {start = start < 0 ? 0 : start; Sort sort = new Sort(Sort.Direction.DESC, "id");Pageable pageable = PageRequest.of(start, limit, sort);Page<Article> page = articleRepository.findAll(pageable);ModelAndView mav = new ModelAndView("admin/article/list");mav.addObject("page", page);return mav;
}
然后,再調用它的參數獲取總頁數、上一頁、下一頁和末頁,見以下代碼。
<div><a th:href="@(/article(start=0)}">[首頁]</a><a th:if="$(not page.isFirst())" th:href="@{/article(start=${page.number-1})}">[上頁]</a><a th:if="$(not page.isLast())" th:href="@(/article(start=$(page.number+1})}">[下頁]</a><a th:href="@{/article(start=$(page.totalPages-1}))">[末頁]</a>
</div>
5.排序類 Sort
Sort 類專門用來處理排序。最簡單的排序就是先傳入一個屬性列,然后根據屬性列的值進行排序。默認情況下是升序排列。它還可以根據提供的多個字段屬性值進行排序。
例如以下代碼是通過 Sort.Order 對象的 List 集合來創建 Sort 對象的:
List<Sort.Order> orders = new ArrayList<>();
orders.add(new Sort.Order(Sort.Direction.DESC, "id"));
orders.add(new Sort.Order(Sort.Direction.ASC, "view"));
Pageable pageable = PageRequest.of(start, limit, sort);
Pageable pageable = PageRequest.of(start, limit, Sort.by(orders));
Sort 排序的方法還有下面幾種:
- 直接創建 Sort 對象,適合對單一屬性做排序。
- 通過 Sort.Order 對象創建 Sort 對象,適合對單一屬性做排序。
- 通過屬性的 List 集合創建 Sort 對象,適合對多個屬性采取同一種排序方式的排序。
- 通過 Sort.Order 對象的 List 集合創建 Sort 對象,適合所有情況,比較容易設置排序方式。
- 忽略大小寫排序。
- 使用 JpaSort.unsafe 進行排序。
- 使用聚合函數進行排序。