Spring Boot中Repository的理解與使用


轉載

原文地址:https://segmentfault.com/a/1190000012346333

一、Repository的概念

在Spring中有Repository的概念,repository原意指的是倉庫,即數據倉庫的意思。Repository居於業務層和數據層之間,將兩者隔離開來,在它的內部封裝了數據查詢和存儲的邏輯。這樣設計的好處有兩個:

  1. 降低層級之間的耦合:更換、升級ORM引擎(Hibernate)並不會影響業務邏輯
  2. 提高測試效率:如果在測試時能用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);
}

<說明>

  1. @RequestParam注解,表明了需要傳入URL參數page和size,用於計算分頁的offset值。
  2. 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);
}

<說明>

  1. 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的基礎上,擴展了部分功能:

  1. 查詢列表(返回值為List)
  2. 批量刪除
  3. 強制同步
  4. Example查詢

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM