1:SpringDataJPA是JPA規范的再次封裝抽象,底層還是使用了Hibernate的JPA技術實現,是屬於Spring的生成體系中的一部分
2:SpringData的結構(七個接口)
操作數據庫的方式一:繼承JpaRepository口后操作數據庫
1:在Repository層新建一個基礎接口
1 @NoRepositoryBean //告訴JPA不要創建對應接口的bean對象 2 public interface BaseReposittory <T,ID extends Serializable> extends JpaRepository<T,ID>{ 3 }
2:再建一個你所要操作的類型的接口去繼承 這里以實體類Employee舉例 這里Long是數據庫中主鍵的類型 完成后就已經具備了基礎的CRUD 和分頁排序的功能
1 public interface EmployeeRepository extends BaseReposittory<Employee,Long>{
注意:在操作數據庫時 添加和修改所使用的都是save()方法 ;可以自行測試 這里測試一個分頁排序
1 @Test//分頁排序 2 public void pageAndSort() throws Exception{ 3 Sort sort = new Sort(Sort.Direction.DESC,"age"); 4 Pageable page = new PageRequest(0,10,sort); 5 Page<Employee> employees = employeeRepository.findAll(page); 6 employees.forEach(e->{ 7 System.out.println(e); 8 }); 9 }
基礎查詢和分頁排序底層已經定義好可以直接使用 現在我們來自定義查詢; 查詢方法寫在EmployeeRepository 中
自定義查詢
方式一:按照規范創建查詢方法,一般按照java駝峰式書寫規范加一些特定關鍵字
例:
1 //根據名稱模糊查詢 2 List<Employee> findByUsernameLike(String username); 3 //根據名稱進行查詢 4 List<Employee> findByUsername(String username);
查詢規則如下:
表達式 |
例子 |
hql查詢語句 |
And |
findByLastnameAndFirstname |
… where x.lastname = ?1 and x.firstname = ?2 |
Or |
findByLastnameOrFirstname |
… where x.lastname = ?1 or x.firstname = ?2 |
Is,Equals |
findByFirstname,findByFirstnameIs,findByFirstnameEqual |
… where x.firstname = 1? |
Between |
findByStartDateBetween |
… where x.startDate between 1? and ?2 |
LessThan(lt) |
findByAgeLessThan |
… where x.age < ?1 |
LessThanEqual(le) |
findByAgeLessThanEqual |
… where x.age <= ?1 |
GreaterThan |
findByAgeGreaterThan |
… where x.age > ?1 |
GreaterThanEqual |
findByAgeGreaterThanEqual |
… where x.age >= ?1 |
After |
findByStartDateAfter |
… where x.startDate > ?1 |
Before |
findByStartDateBefore |
… where x.startDate < ?1 |
IsNull |
findByAgeIsNull |
… where x.age is null |
IsNotNull,NotNull |
findByAge(Is)NotNull |
… where x.age not null |
Like |
findByFirstnameLike |
… where x.firstname like ?1 |
NotLike |
findByFirstnameNotLike |
… where x.firstname not like ?1 |
StartingWith |
findByFirstnameStartingWith |
… where x.firstname like ?1 (parameter bound with appended %) |
EndingWith |
findByFirstnameEndingWith |
… where x.firstname like ?1 (parameter bound with prepended %) |
Containing |
findByFirstnameContaining |
… where x.firstname like ?1 (parameter bound wrapped in %) |
OrderBy |
findByAgeOrderByLastnameDesc |
… where x.age = ?1 order by x.lastname desc |
Not |
findByLastnameNot |
… where x.lastname <> ?1 |
In |
findByAgeIn(Collection ages) |
… where x.age in ?1 |
NotIn |
findByAgeNotIn(Collection age) |
… where x.age not in ?1 |
True |
findByActiveTrue() |
… where x.active = true |
False |
findByActiveFalse() |
… where x.active = false |
IgnoreCase |
findByFirstnameIgnoreCase |
… where UPPER(x.firstame) = UPPER(?1) |
方式二:@Query注解查詢
在EmployeeRepository 按照查詢方法的命名規則,其實是比較麻煩的如果我們想不遵循 查詢方法的命名規則,還可以使用@Query的方法進行查詢。只需要將@Query定義在Respository的方法之上即可
1:使用jpql語句操作數據庫
例:
1 //根據用戶名查詢(這里寫必需在問號后加順序) 2 @Query("select e from Employee e where e.username = ?1") 3 Employee query01(String name); 4 //根據用戶名模糊查詢(這里寫必需在問號后加順序) 5 @Query("select e from Employee e where e.username like ?1") 6 List<Employee> query02(String name); 7 //根據用戶名與郵件進行模糊查詢(這里寫必需在問號后加順序) 8 @Query("select e from Employee e where e.username like ?1 and e.email like ?2") 9 List<Employee> query03(String name, String email);
2:如果想用原生sql操作數據庫只需在注解@Query中加nativeQuery =true
例:
1 //查詢所有 2 @Query(nativeQuery =true,value = "select * from employee where username=?;") 3 Employee query04(String name);
方式三:繼承接口JpaSpecificationExecutor
JpaSpecificationExecutor的認識
JpaSpecificationExecutor(JPA規則執行者)是JPA2.0提供的Criteria API的使用封裝,可以用於動態生成Query來滿足我們業務中的各種復雜場景。
Spring Data JPA為我們提供了JpaSpecificationExecutor接口,只要簡單實現toPredicate方法就可以實現復雜的查詢。所有查詢都要求傳入一個Specification對象
1:BaseReposittory的操作
@NoRepositoryBean //告訴JPA不要創建對應接口的bean對象 public interface BaseReposittory <T,ID extends Serializable> extends JpaRepository<T,ID>,JpaSpecificationExecutor<T> { }
2:測試:直接來個多條件查詢
1 /** 2 * 根據相應的規則(Specification) 查詢對應數據 3 * Predicate: where username=? and email =? 4 * root : 根 -> 可以獲取到類中的屬性(username,email) 5 * criteriaQuery: 如select,from,where,group by ,order by 等 6 * criteriaBuilder:解決 username=? / username like ? / age > ? 7 * 多個條件結合 username=? and/or age > ? 8 */ 9 @Test//多條件查詢+分頁+排序 10 public void testJpaSpecificationExecutor() throws Exception{ 11 //先定義規范 12 Specification spec= new Specification<Employee>() { 13 @Override 14 public Predicate toPredicate(Root<Employee> root, CriteriaQuery<?> cq, CriteriaBuilder cd) { 15 Path usernamePath = root.get("username"); 16 Predicate p1 = cd.like(usernamePath, "%1%"); 17 Path emailPath = root.get("email"); 18 Predicate p2 = cd.like(emailPath, "%2%"); 19 Path agePath = root.get("age"); 20 Predicate p3 = cd.ge(agePath, 18);//le 表示小於 ge表示大於 21 //多個條件連接起來 22 Predicate p = cd.and(p1, p2, p3); 23 return p; 24 } 25 }; 26 //進行排序 27 Sort sort = new Sort(Sort.Direction.ASC,"username"); 28 //進行分頁 29 Pageable page=new PageRequest(0,10,sort); 30 //查詢數據庫 31 Page p = employeeRepository.findAll(spec, page); 32 p.forEach(e->{ 33 System.out.println(e); 34 }); 35 }
Root:查詢哪個表(定位到表和字段-> 用於拿到表中的字段)
* 可以查詢和操作的實體的根
* Root接口:代表Criteria查詢的根對象,Criteria查詢的查詢根定義了實體類型,能為將來導航獲得想要的結果,它與SQL查詢中的FROM子句類似
* Root<Employee> 相當於 from Employee
* Root<Product> 相當於 from Product
* CriteriaQuery:查詢哪些字段,排序是什么(主要是把多個查詢的條件連系起來)
* CriteriaBuilder:字段之間是什么關系,如何生成一個查詢條件,每一個查詢條件都是什么方式
* 主要判斷關系(和這個字段是相等,大於,小於like等)
* Predicate(Expression):單獨每一條查詢條件的詳細描述 整個 where xxx=xx and yyy=yy ...
方式四:使用jpa-spec插件的前提是要實現JpaSpecificationExecutor接口(我這里是接口繼承了接口)
1:在Maven項目中pom.xml引入包
<!-- jpa的SpecificationSpecification功能封裝 --> <dependency> <groupId>com.github.wenhao</groupId> <artifactId>jpa-spec</artifactId> <version>3.1.1</version> <!-- 把所有依賴都過濾 --> <exclusions> <exclusion> <groupId>*</groupId> <artifactId>*</artifactId> </exclusion> </exclusions> </dependency>
2:功能測試:
1 @Test// 多個條件查詢 +分頁+排序 2 public void testSpec() throws Exception{ 3 Specification<Employee> spec = Specifications.<Employee>and() 4 .like("username","%1%") 5 .like("email","%2%") 6 .ge("age", 20) 7 .build(); 8 Sort sort = new Sort(Sort.Direction.DESC,"age");//根據年齡排序 9 Pageable page = new PageRequest(0,10,sort); 10 Page<Employee> list = employeeRepository.findAll(spec, page); 11 list.forEach(e->{ 12 System.out.println(e); 13 }); 14 }