由於最近項目要選擇使用Spring Data JPA,因此不得不去學習一波,記錄一下學習過程遇到的問題,以此謹記於心。java
Spring Data存儲庫抽象中的中央接口是Repository,Spring Data JPA只是Spring Data中的一個子模塊,JPA是一套標準接口,而Hibernate是JPA的實現,它須要域類以及域類的ID類型做爲類型參數來進行管理。該接口主要用做標記接口,以捕獲要使用的類型並幫助您發現擴展該接口的接口,Spring Data JPA經常使用的接口是JpaRepository,JpaRepository繼承了接口PagingAndSortingRepository和QueryByExampleExecutor,具有較全的方法。正則表達式
在這裏我選擇幾個Spring Data JPA比較重要的對象進行介紹和源碼解析,幫助咱們理解:數據庫
QueryByExampleExecutor | 支持動態查詢,不支持過濾條件分組,即不支持夠快提哦啊見用or來鏈接,全部的裸鋁條件都是簡單一層的用and鏈接,eg:firstname=?1 or(firstname=?1 and lastname=?2),只支持字符串的開始/包含/結束/正則表達式匹配和其餘屬性類型的精確匹配 |
PagingAndSortingRepository | CrudRepository的子接口,添加分頁和排序的功能 |
JpaRepository | PagingAndSortingRepository的子接口,增長了一些實用的功能,好比:批量操做等。 |
PageRequest | Spring Data JPA的分頁對象,直接用 PageRequest.of這個方法來建立Pageable分頁對象 |
QueryByExampleExecutor源碼,具體方法做用我已經標註上:框架
public interface QueryByExampleExecutor<T> { //根據實例查看一個對象 <S extends T> Optional<S> findOne(Example<S> var1); //根據實例查找一批對象 <S extends T> Iterable<S> findAll(Example<S> var1); //根據實例查找一批對象,且排序 <S extends T> Iterable<S> findAll(Example<S> var1, Sort var2); //根據實例查找一批對象,排序且分頁 <S extends T> Page<S> findAll(Example<S> var1, Pageable var2); //根據實例查找返回符合條的件對象個數 <S extends T> long count(Example<S> var1); //根據實例判斷是否有符合條件的對象 <S extends T> boolean exists(Example<S> var1); }
說以咱們看Example基本上就能夠掌握它的用法和API了,Example接口:源碼分析
public interface Example<T> { static <T> Example<T> of(T probe) { return new TypedExample(probe, ExampleMatcher.matching()); } static <T> Example<T> of(T probe, ExampleMatcher matcher) { return new TypedExample(probe, matcher); } T getProbe(); ExampleMatcher getMatcher(); default Class<T> getProbeType() { return ProxyUtils.getUserClass(this.getProbe().getClass()); } }
從源碼咱們能夠看出Example主要包括三部份內容:學習
QueryByExampleExecutor使用實例:this
Book book= new Book(); book.setName("Java"); book.setAuthor("林必昭"); ExampleMatcher matcher = ExampleMatcher.matching() .withMatcher("name", ExampleMatcher.GenericPropertyMatchers.startsWith()) //書籍名稱採用"開始匹配"的方式查詢 .withMatcher("author",ExampleMatcher.GenericPropertyMatchers.exact()) //書籍做者採用"精確匹配"的方式查詢 .withIgnorePaths("focus"); //忽略屬性,是否關注。由於是基本類型,須要忽略掉 //建立實例 Example<Book> ex = Example.of(book,matcher); //查詢 List<Book> bookList = bookDao.findAll(ex); //輸出結果 for(Book book:bookList){ System.out.println(book.getName()); }
PagingAndSortingRepository源碼,PagingAndSortingRepository接口繼承了CrudRepository接口:spa
@NoRepositoryBean public interface PagingAndSortingRepository<T, ID> extends CrudRepository<T, ID> { //具備排序功能 Iterable<T> findAll(Sort var1); //具備分頁功能 Page<T> findAll(Pageable var1); }
JpaRepository源碼分析:.net
@NoRepositoryBean public interface JpaRepository<T, ID> extends PagingAndSortingRepository<T, ID>, QueryByExampleExecutor<T> { //查詢全部 List<T> findAll(); //查詢全部並排序 List<T> findAll(Sort var1); //根據ID進行查找 List<T> findAllById(Iterable<ID> var1); //保存 <S extends T> List<S> saveAll(Iterable<S> var1); //save不會當即提交到數據庫,flush則是當即提交生次 void flush(); //保存並當即提交到數據庫 <S extends T> S saveAndFlush(S var1); //批量刪除 void deleteInBatch(Iterable<T> var1); void deleteAllInBatch(); //獲取對象 T getOne(ID var1); //查詢全部 <S extends T> List<S> findAll(Example<S> var1); <S extends T> List<S> findAll(Example<S> var1, Sort var2); }
PageRequest的源碼:code
public class PageRequest extends AbstractPageRequest { private static final long serialVersionUID = -4541509938956089562L; private final Sort sort; /** @deprecated */ @Deprecated public PageRequest(int page, int size) { this(page, size, Sort.unsorted()); } /** @deprecated */ @Deprecated public PageRequest(int page, int size, Direction direction, String... properties) { this(page, size, Sort.by(direction, properties)); } /** @deprecated */ @Deprecated public PageRequest(int page, int size, Sort sort) { super(page, size); this.sort = sort; } public static PageRequest of(int page, int size) { return of(page, size, Sort.unsorted()); } public static PageRequest of(int page, int size, Sort sort) { return new PageRequest(page, size, sort); } public static PageRequest of(int page, int size, Direction direction, String... properties) { return of(page, size, Sort.by(direction, properties)); } public Sort getSort() { return this.sort; } public Pageable next() { return new PageRequest(this.getPageNumber() + 1, this.getPageSize(), this.getSort()); } public PageRequest previous() { return this.getPageNumber() == 0 ? this : new PageRequest(this.getPageNumber() - 1, this.getPageSize(), this.getSort()); } public Pageable first() { return new PageRequest(0, this.getPageSize(), this.getSort()); } public boolean equals(@Nullable Object obj) { if (this == obj) { return true; } else if (!(obj instanceof PageRequest)) { return false; } else { PageRequest that = (PageRequest)obj; return super.equals(that) && this.sort.equals(that.sort); } } public int hashCode() { return 31 * super.hashCode() + this.sort.hashCode(); } public String toString() { return String.format("Page request [number: %d, size %d, sort: %s]", this.getPageNumber(), this.getPageSize(), this.sort); } }
下面列舉一些注意事項,是在學習中總結出來的,很重要:
關於JPA的排序的幾種實現方法:
下面我列舉每一種的實現方法來加以說明排序的實現:
1.基於參數排序
//創建分頁對象
Pageable pageable = new PageRequest(PageNum,PageSize);
//在Respository定義方法
Page<Entity>findCustomerByFirstNameOrderByIdAsc(Pageabe pageble);
2.基於自定義的@Query進行排序
@Query("select c from Customer c ORDER BY c.id ASC,c.firstName DESC")
List<Customer> findCustomerByFirstNameOrderByIdAsc();
3.基於Pageable中的Sort字段
Sort sort1 = new Sort(Sort.Direction.ASC,"id");
Pageable pageable = PageRequest.of(pageNum,pageSize,sort1);//在service調用具體的Repository的方法
Page<Customer> Customers = customerRepository.findAll(pageable);
4.直接建立Sort對象,適合對單一屬性作排序
Sort sort1 = new Sort(Sort.Direction.ASC,"id");
List<Customer> customerListAsc = customerRepository.findByName3AndSort("Bauer", sort1);
5.經過屬性的List集合建立Sort對象,適合對多個屬性
List<String> sortProperties = new ArrayList<>();
sortProperties.add("id");
sortProperties.add("firstName");Sort sort2 = new Sort(Sort.Direction.ASC,sortProperties);
List<Customer> result2 = customerRepository.findByName3AndSort("Bauer", sort2);
6.經過Sort.Order對象的List集合建立Sort對象
//經過建立Sort.Order對象的集合建立sort對象
System.out.println("經過建立Sort.Order對象的集合建立sort對象");
List<Sort.Order> orders = new ArrayList<>();
orders.add(new Sort.Order(Sort.Direction.DESC,"id")); //id降序
orders.add(new Sort.Order(Sort.Direction.ASC,"firstName")); //firstName升序// List<Customer> result3 = customerRepository.findByName3AndSort("Bauer", new Sort(orders));
List<Customer> result3 = customerRepository.findByName3AndSort("Bauer", Sort.by(orders));
對於第六種方法,適合對多個屬性,採用不一樣的排序方式排序,比較實用,JPA已經將public Sort(List<Sort.Order> orders) {}方法棄用了,也就是我註釋掉的那個方法,使用 public static Sort by(List<Sort.Order> orders) {}代替:
public static Sort by(List<Sort.Order> orders) { Assert.notNull(orders, "Orders must not be null!"); return orders.isEmpty() ? unsorted() : new Sort(orders); }
關於使用原生SQL和JPQL的區別,下面舉個栗子來講明:
問題實現:根據姓名來查詢客戶;
SQL的實現:
@QueryHints(value = {@QueryHint(name = HINT_COMMENT, value = "a query for pageable")})
@Query(nativeQuery = true,value = "select * from customer c where c.first_name=:name or c.last_name=:name")
Page<Customer> findByName(@Param("name") String name3, Pageable pageable);
JPQL的實現:
@QueryHints(value = {@QueryHint(name = HINT_COMMENT, value = "a query for pageable")})
@Query("select c from Customer c where c.firstName=:name or c.lastName=:name")
Page<Customer> findByName(@Param("name") String name3, Pageable pageable);
總結:原生的SQL直接使用數據庫表名和數據庫屬性名,JPQL會將數據庫映射成實體,使用JPQL更直觀我以爲!!
今天的學習就到這裏,還會有下一篇關於Spring Data JPA 深刻學習篇(二),但願一比一步從入門到掌握再到精通,一塊兒期待吧!!!