Repository接口
- 是什么
Repository是一個空接口,即:是一個標記接口,表示任何繼承它的接口都是倉庫接口類- 若我們繼承了
Repository,則該接口會被Ioc容器表示為一個Repository Bean,放入到IOC容器中,進而可以在該接口中定義滿足一定規范的方法 - 實際上也可以通過
@RepositoryDefinition(domainClass = Person.class, idClass = Long.class)來替代繼承Repository接口
- 子接口
CrudRepository:繼承Repository,實現一組CURD相關的方法PagingAndSortingRespository:繼承CrudRepository,實現了一組分頁排序相關的方法JpaRepository:繼承PagingAndSortingRespository,實現了一組JPA規范相關的方法- 自定義的
XxxRepository:需要繼承JpaRepository,這樣該接口就具備了通用的數據訪問控制層的能力 JpaSpecificationExecutor:不屬於Repository體系,實現一組JPA Criteria查詢相關的方法
Repository 查詢方法定義規范
1. 查詢方法
-
方法必須以
find|read|get開頭 -
涉及查詢條件時,條件的實行用條件關鍵字連接,
- 注意:條件屬性需要首字母大寫
-
支持屬性的級聯查詢
-
若當前類有符合條件的屬性,會優先使用屬性,而不是使用級聯屬性
-
若要使用級聯屬性,則屬性之間用 _ 連接。而為了避免歧義,推薦使用 _ 分隔的寫法。如:
// Address類 @Entity @Table(name = "t_address") public class Address implements Serializable { private static final long serialVersionUID = -682608034116202529L; @Id @GeneratedValue(strategy = GenerationType.IDENTITY) private Long id; private String province; private String city; @ManyToOne @JoinColumn(name = "person_id") private Person person; } // Person類 @Entity @Table(name = "t_person") public class Person implements Serializable { private static final long serialVersionUID = -5964437048712784999L; @Id @GeneratedValue(strategy = GenerationType.IDENTITY) private Long id; private String name; private Integer age; private String gender; private String email; @Column(name = "address_id") // 搗亂的字段 private Long addressId; @OneToMany(mappedBy = "person") private Set<Address> address = new HashSet<>(); } // PersonDao中的getByAddress_Id必須使用 _ 分隔,而不能直接寫 getByAddressId public interface PersonDao extends Repository<Person, Long> { List<Person> getByNameLike(String name); Person getByAddress_Id(Long id); } -
缺點:
- 方法名很長
- 不能用於子查詢
-
2. 注解
-
@Query
-
可以執行自定義的JPQL語句以更靈活的查詢
// 查詢id最大的那個person @Query("from Person p1 where p1.id = (select max(p2.id) from Person p2)") Person getPersonByMaxId(); -
注解傳遞參數
-
使用占位符:參數順序必須和JPQL中的順序一致
@Query("from Person p where p.name = ?1 and p.gender = ?2") Person query_getPersonByNameAndGender(String name, String gender); -
使用命名參數:這種寫法可以隨便設置參數順序
@Query("from Person p where p.name = :name and p.age = :age") Person query_getPersonByNameAndAge(@Param("age") Integer age, @Param("name") String name);- @Param:
org.springframework.data.repository.query.Param;
- @Param:
-
-
spring data允許在占位符上添加%(適用於模糊查詢like:
%占位符%) -
@Query支持原生sql查詢
@Query(value = "select count(1) from t_person", nativeQuery = true) Long getTotal();
-
-
@Modifying:可以使用該注解來實現通過JPQL修改和刪除(JPQL不支持添加)
@Modifying @Query(value = "update Person p set p.name = ?1, p.age = ?2 where p.id = ?3") void updatePerson(String name, Integer age, Long id);- 注意:更新和刪除操作需要事務支持
- 在@Query中編寫JPQL語句,但是必須添加@Modifying進行修飾來告訴JPA這是修改的操作
- 為什么@Query可以執行呢?
- 所有的
Repository方法都有一個事務,但是卻是只讀事務
- 所有的
3. CRUDRepository
- 這個接口提供了基本增刪改查方法
4. PagingAndSortingRepository
-
該接口提供了排序和分頁的方法:方法的參數Pagable里面包含的有Sort
-
測試
-
測試分頁:pageNum(頁碼)從0開始計數
@Test public void test08() { Pageable pageable = PageRequest.of(0, 10); Page<Person> personPage = personDao.findAll(pageable); System.out.println("總記錄條數:" + personPage.getTotalElements()); System.out.println("總頁數:" + personPage.getTotalPages()); System.out.println("當前頁:" + personPage.getNumber()); System.out.println("當前頁內容(數據):" + personPage.getContent()); System.out.println("當前頁記錄數:" + personPage.getNumberOfElements()); } -
測試排序
@Test public void test09() { Sort sort = Sort.by(Sort.Direction.DESC, "id"); Iterable<Person> persons = personDao.findAll(sort); persons.forEach(System.out::println); } -
測試分頁排序
@Test public void test10() { // Pageable pageable = PageRequest.of(0, 10, Sort.Direction.DESC, "age", "id"); // Sort sort = Sort.by(Sort.Direction.DESC, "age", "id"); Sort.Order order1 = new Sort.Order(Sort.Direction.DESC, "age"); Sort.Order order2 = new Sort.Order(Sort.Direction.ASC, "name"); Sort sort = Sort.by(order1, order2); Pageable pageable = PageRequest.of(0, 10, sort); Page<Person> personPage = personDao.findAll(pageable); personPage.forEach(System.out::println); }
-
5. JpaRepository
-
JpaRepository中定義了一些新的方法,最主要是批量操作的方法 -
方法
2. <S extends T> List<S> saveAll(Iterable<S> var1):批量保存-
void flush():刷新。同步Jpa緩存和數據庫
-
<S extends T> S saveAndFlush(S var1):相當於JPA的merge方法
-
void deleteInBatch(Iterable<T> var1):批量刪除
-
void deleteAllInBatch():批量刪除所有
-
6. JpaSpecificationExecutor
-
通過查詢條件查詢
-
方法
-
Optional<T> findOne(@Nullable Specification<T> spec):根據條件查詢 -
findAll:查詢所有-
List<T> findAll(@Nullable Specification<T> spec):根據條件查詢所有 -
Page<T> findAll(@Nullable Specification<T> spec, Pageable pageable):根據條件分頁[排序] -
List<T> findAll(@Nullable Specification<T> spec, Sort sort):根據條件排序
-
-
long count(@Nullable Specification<T> spec):查詢數量
-
-
Specification接口:Predicate toPredicate(Root<T> root, CriteriaQuery<?> query, CriteriaBuilder criteriaBuilder);- 該接口通常使用匿名內部類
- Predicate 代表查詢條件
- Root 代表查詢的實體類對象
- CriteriaQuery 可以從中查詢到 root 對象,還可以用來添加查詢條件,還可以結合EntityManager獲取最終查詢的
TypeQuery對象 - CriteriaBuilder 用於創建Criteria相關對象的工廠,當然可以從中獲取到 Predicate 對象
本節代碼:點擊此處
