轉載
原文地址:https://segmentfault.com/a/1190000012346333
一、Repository的概念
在Spring中有Repository的概念,repository原意指的是倉庫,即數據倉庫的意思。Repository居於業務層和數據層之間,將兩者隔離開來,在它的內部封裝了數據查詢和存儲的邏輯。這樣設計的好處有兩個:
- 降低層級之間的耦合:更換、升級ORM引擎(Hibernate)並不會影響業務邏輯
- 提高測試效率:如果在測試時能用Mock數據對象代替實際的數據庫操作,運行速度會快很多
二、Repository和DAO的區別
DAO是傳統MVC中Model的關鍵角色,全稱是Data Access Object。DAO直接負責數據庫的存取工作,乍一看兩者非常類似,但從架構設計上講兩者有着本質的區別:
Repository蘊含着真正的OO概念,即一個數據倉庫角色,負責所有對象的持久化管理。DAO則沒有擺脫數據的影子,仍然停留在數據操作的層面上。Repository是相對對象而言,DAO則是相對數據庫而言,雖然可能是同一個東西 ,但側重點完全不同
三、三種Repository介紹
在Spring和Spring Data JPA中,有三種Repository接口方便開發者直接操作數據倉庫。
它們之間的關系如下:
CrudRepository
<S extends T> S save(S entity); <S extends T> Iterable<S> save(Iterable<S> entities); T findOne(ID id); boolean exists(ID id); Iterable<T> findAll(); Iterable<T> findAll(Iterable<ID> ids); long count(); void delete(ID id); void delete(T entity); void delete(Iterable<? extends T> entities); void deleteAll();
CrudRepository類如其名,可以勝任最基本的CRUD操作。其中save方法在可兩用,參數中不存在主鍵時執行insert操作,存在主鍵則執行update操作,相當於是一個upsert操作。
PagingAndSortingRepository
Iterable<T> findAll(Sort sort);
Page<T> findAll(Pageable pageable);
PagingAndSortingRepository繼承了CrudRepository接口,增加了分頁和排序的方法。
分頁
要達到分頁的目的,需要傳入一個Pageble接口對象,controller中代碼如下:
@GetMapping("") public ResponseEntity<?> getList( @RequestParam(value="page", defaultValue="0") int page, @RequestParam(value="size", defaultValue="10") int size ) { Pageable pageable = new PageRequest(page, size); return new ResponseEntity<Object>(userService.getUserList(pageable), HttpStatus.OK); }
<說明>
- @RequestParam注解,表明了需要傳入URL參數page和size,用於計算分頁的offset值。
- PageRequest是Pageable的實現類,傳入初始化page和size即可生成分頁參數。
在Service中,僅需加入pageable對象即可達到分頁的效果。代碼如下:
public Iterable<User> getUserList(Pageable pageable) { return userRepo.findAll(pageable); }
此時在POSTMAN中輸入訪問地址:'127.0.0.1:8080/user?page=0&size=5',得到以下結果:
{ "content": [ { "id": 12, "name": "F1" }, { "id": 13, "name": "A" }, { "id": 14, "name": "B" }, { "id": 15, "name": "C" }, { "id": 16, "name": "D" } ], "last": false, "totalPages": 3, "totalElements": 11, "size": 5, "number": 0, "numberOfElements": 5, "first": true, "sort": null }
從結果可以看出,不僅在content中有查詢的數組信息,還包括totalPages等分頁信息。
排序
與分頁類似,要達到排序的目錄,僅需要傳入Sort對象即可,controller中代碼如下:
@GetMapping("") public ResponseEntity<?> getList( @RequestParam(value="page", defaultValue="0") int page, @RequestParam(value="size", defaultValue="10") int size ) { Sort sort = new Sort(Sort.Direction.DESC, "name"); // Pageable pageable = new PageRequest(page, size); return new ResponseEntity<Object>(userService.getUserList(sort), HttpStatus.OK); }
同樣的,在Service中需要新增接口,如下:
public Iterable<User> getUserList(Sort sort) { return userRepo.findAll(sort); }
此時在POSTMAN中輸入訪問地址:'127.0.0.1:8080/user',得到以下結果:
[ { "id": 22, "name": "K" }, { "id": 21, "name": "J" }, { "id": 20, "name": "I" }, { "id": 19, "name": "H" }, { "id": 18, "name": "G" }, { "id": 12, "name": "F1" }, { "id": 17, "name": "E" }, { "id": 16, "name": "D" }, { "id": 15, "name": "C" }, { "id": 14, "name": "B" }, { "id": 13, "name": "A" } ]
得到的正是name屬性按DESC排序的結果列表
排序后分頁
PagingAndSortingRepository提供了分頁和排序的接口,那如果兩者都要做,該怎么寫呢?
其實在Pageable中,還可以傳入Sort屬性,這樣就可以在分頁中達到排序的目的。
同樣的,把Controller代碼稍稍調整一下:
@GetMapping("") public ResponseEntity<?> getList( @RequestParam(value="page", defaultValue="0") int page, @RequestParam(value="size", defaultValue="10") int size ) { Sort sort = new Sort(Sort.Direction.DESC, "name"); Pageable pageable = new PageRequest(page, size, sort); return new ResponseEntity<Object>(userService.getUserList(pageable), HttpStatus.OK); }
<說明>
- Sort對象作為PageRequest的第三個參數傳入。
這樣調整以后,UserService這邊就不在需要入參為Sort的getUserList接口了。
此時在POSTMAN中輸入訪問地址:'127.0.0.1:8080/user?page=0&size=5',得到以下結果:
{ "content":[ {"id":22,"name":"K"}, {"id":21,"name":"J"}, {"id":20,"name":"I"}, {"id":19,"name":"H"}, {"id":18,"name":"G"} ], "totalPages":3, "totalElements":11, "last":false,"size":5, "number":0, "first":true, "numberOfElements":5, "sort":[{ "direction":"DESC", "property":"name", "ignoreCase":false, "nullHandling":"NATIVE", "ascending":false, "descending":true }] }
JpaRepository
List<T> findAll(); List<T> findAll(Sort sort); List<T> findAll(Iterable<ID> ids); <S extends T> List<S> save(Iterable<S> entities); void flush(); <S extends T> S saveAndFlush(S entity); void deleteInBatch(Iterable<T> entities); void deleteAllInBatch(); T getOne(ID id); @Override <S extends T> List<S> findAll(Example<S> example); @Override <S extends T> List<S> findAll(Example<S> example, Sort sort);
JpaRepository則進一步在PagingAndSorting的基礎上,擴展了部分功能:
- 查詢列表(返回值為List)
- 批量刪除
- 強制同步
- Example查詢