spring data jpa 可以通過(guò)在接口中按照規(guī)定語(yǔ)法創(chuàng)建一個(gè)方法進(jìn)行查詢(xún),spring data jpa 基礎(chǔ)接口中,如CrudRepository中findOne,save,delete等,那么我們自己怎么按照需要?jiǎng)?chuàng)建一個(gè)方法進(jìn)行查詢(xún)呢?
- 最常見(jiàn)的做法是聲明一個(gè)接口繼承于CrudRepository 或者 PagingAndSortingRepository,JpaRepository,Repository
public interface TaskDao extends JpaRepository<Task,Long>{
}
或者利用注釋的方式表名繼承于JpaRepository,例如下面這倆種是等價(jià)的
@RepositoryDefinition(domainClass = Task.class, idClass = Long.class)
public interface TaskDao{
}
public interface TaskDao extends JpaRepository<Task,Long>{
}
繼承CrudRepository 或者 PagingAndSortingRepository,JpaRepository會(huì)抽出一些常用的方法,如果你spring data jpa幫你自定義那么多方法,你可以繼承于JpaRepository,然后復(fù)制一些方法到你的接口中,可以選擇性的要一些方法
@NoRepositoryBean
interface MyBaseRepository<T, ID extends Serializable> extends Repository<T, ID> {
T findOne(ID id);
T save(T entity);
}
interface TaskDao extends MyBaseRepository<Task, Long> {
}
- 按照規(guī)范創(chuàng)建查詢(xún)方法,一般按照java駝峰式書(shū)寫(xiě)規(guī)范加一些特定關(guān)鍵字,例如我們想通過(guò)任務(wù)名來(lái)獲取任務(wù)實(shí)體類(lèi)列表
利用屬性獲取任務(wù)列表
interface TaskDao extends MyBaseRepository<Task, Long> {
List<Task> findByName(String name);
}
利用and 和 or來(lái)獲取任務(wù)列表
interface TaskDao extends JpaRepository<Task, Long> {
List<Task> findByNameAndProjectId(String name,Long projectId);
List<Task> findByNameOrProjectId(String name,Long projectId);
}
利用Pageable ,Sort,Slice獲取分頁(yè)的任務(wù)列表和排序
interface TaskDao extends JpaRepository<Task, Long> {
Page<Task> findByName(String name,Pageable pageable);
Slice<Task> findByName(String name, Pageable pageable);
List<Task> findByName(String name, Sort sort);
}
利用Distinct去重
interface TaskDao extends JpaRepository<Task, Long> {
List<Person> findDistinctTaskByNameOrProjectId(String name, Long projectId);
}
利用OrderBy進(jìn)行排序
interface TaskDao extends JpaRepository<Task, Long> {
List<Person> findByNameOrderByProjectIdDesc(String name, Long projectId);
}
利用 Top 和 First來(lái)獲取限制數(shù)據(jù)
interface TaskDao extends JpaRepository<Task, Long> {
User findFirstByOrderByLastnameAsc();
Task findTopByOrderByNameDesc(String name);
Page<Task> queryFirst10ByName(String name, Pageable pageable);
Slice<Task> findTop3ByName(String name, Pageable pageable);
List<Task> findFirst10ByName(String name, Sort sort);
List<Task> findTop10ByName(String name, Pageable pageable);
}
那么spring data jpa是怎么通過(guò)這些規(guī)范來(lái)進(jìn)行組裝成查詢(xún)語(yǔ)句呢?
Spring Data JPA框架在進(jìn)行方法名解析時(shí),會(huì)先把方法名多余的前綴截取掉,比如 find、findBy、read、readBy、get、getBy,然后對(duì)剩下部分進(jìn)行解析。
假如創(chuàng)建如下的查詢(xún):findByTaskProjectName(),框架在解析該方法時(shí),首先剔除 findBy,然后對(duì)剩下的屬性進(jìn)行解析,假設(shè)查詢(xún)實(shí)體為Doc
先判斷 taskProjectName (根據(jù) POJO 規(guī)范,首字母變?yōu)樾?xiě))是否為查詢(xún)實(shí)體的一個(gè)屬性,如果是,則表示根據(jù)該屬性進(jìn)行查詢(xún);如果沒(méi)有該屬性,繼續(xù)第二步; 從右往左截取第一個(gè)大寫(xiě)字母開(kāi)頭的字符串此處為Name),然后檢查剩下的字符串是否為查詢(xún)實(shí)體的一個(gè)屬性,如果是,則表示根據(jù)該屬性進(jìn)行查詢(xún);如果沒(méi)有該屬性,則重復(fù)第二步,繼續(xù)從右往左截取;最后假設(shè)task為查詢(xún)實(shí)體Person的一個(gè)屬性; 接著處理剩下部分(ProjectName),先判斷 task 所對(duì)應(yīng)的類(lèi)型是否有projectName屬性,如果有,則表示該方法最終是根據(jù) “ Person.task.projectName”的取值進(jìn)行查詢(xún);否則繼續(xù)按照步驟 2 的規(guī)則從右往左截取,最終表示根據(jù) “Person.task.project.name” 的值進(jìn)行查詢(xún)。 可能會(huì)存在一種特殊情況,比如 Person包含一個(gè) task 的屬性,也有一個(gè) projectName 屬性,此時(shí)會(huì)存在混淆??梢悦鞔_在屬性之間加上 “_” 以顯式表達(dá)意圖,比如 “findByTask_ProjectName()”
支持的規(guī)范表達(dá)式,這里以實(shí)體為User,有firstName和lastName,age
表達(dá)式 |
例子 |
hql查詢(xún)語(yǔ)句 |
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 |
findByAgeLessThan |
… where x.age < ?1 |
LessThanEqual |
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) |
發(fā)現(xiàn)這些查詢(xún)都是只針對(duì)單表進(jìn)行查詢(xún),如果是多表的復(fù)雜查詢(xún),還有分頁(yè)該怎么查,下次再研究看看…
|