javascript
Spring Data(二)查询
Spring Data(二)查詢
接著上一篇,我們繼續講解Spring Data查詢的策略。
查詢的生成
查詢的構建機制對于Spring Data的基礎是非常有用的。構建的機制將截斷前綴find…By、read…By、query…By、count…By、get…By等,從剩余的部分開始解析。省略號可以進一步使用distinct等關鍵字創建查詢。第一個By作為分界符,后面的部分將開始解析。最基礎的,你可以使用實體中的屬性定義條件并且可以使用And或Or連接它們。
方法名字生成查詢:
interface PersonRepository extends Repository<User, Long> {List<Person> findByEmailAddressAndLastname(EmailAddress emailAddress, String lastname);// 使用distinct關鍵字構建查詢List<Person> findDistinctPeopleByLastnameOrFirstname(String lastname, String firstname);List<Person> findPeopleDistinctByLastnameOrFirstname(String lastname, String firstname);// Enabling ignoring case for an individual propertyList<Person> findByLastnameIgnoreCase(String lastname);// Enabling ignoring case for all suitable propertiesList<Person> findByLastnameAndFirstnameAllIgnoreCase(String lastname, String firstname);// 在查詢中使用OrderByList<Person> findByLastnameOrderByFirstnameAsc(String lastname);List<Person> findByLastnameOrderByFirstnameDesc(String lastname); }解析方法的實際結果取決于持久化的存儲,但是其中有一些通用的東西要告訴大家:
- 表達式通常遍歷屬性并且使用操作符連接。你可以連接屬性使用表達式And或者Or,也可以使用其他的操作符Between、LessThan、GreaterThan、Like等。被支持的操作符非常的廣泛,你可以查詢適合的相關文檔。
- 方法解析器支持單個屬性設置IgnoreCase的標識(例如:findByLastnameIgnoreCase(…)),或者一個類型的所有屬性設置ignoring case(例如:findByLastnameAndFirstnameAllIgnoreCase(…))。不管ignoring cases是不是被廣大的數據庫支持,都要查詢指定數據庫的相關文檔。
- 你可以使用OrderBy使方法查詢排序。
屬性表達式
屬性表達式僅僅涉及一個被管理實體的屬性。在查詢生成時,你已經確定解析的屬性就是你管理的實體類中的屬性。你也可以通過嵌套屬性定義約束,假設一個Person類有一個Address類,Address類有一個ZipCode類,方法的命名如下:
List<Person> findByAddressZipCode(ZipCode zipCode);生成的屬性嵌套為:x.address.zipCode。解決的邏輯是從AddressZipCode開始,用這個名字(開頭字母小寫)去檢查屬性,如果找到了,就檢查這個屬性。如果沒有找到,將從右側按照駝峰規則進行分割,分割成一個頭和一個尾,然后嘗試找到合適的屬性,我們的例子中,分割層AddressZip和Code。接著,如果用頭找到了合適的屬性,會用尾繼續向下一層查找,將尾部按照上面的描述那樣繼續分割。如果第一次分割沒有匹配成功,將分割點左移(Address和ZipCode)并繼續。
雖然這中邏輯可以為大多數情況下工作,但是它也有可能選擇錯誤的屬性。假設Person也有一個addressZip的屬性,這種邏輯將匹配第一次分割,選擇了錯誤的屬性并最終失敗(addressZip沒有code字段)。
為了解決中模糊不清的含義,我們可以在方法名字中使用“_”手動創建分割點。所以我們的方法名字如下:
List<Person> findByAddress_ZipCode(ZipCode zipCode);我們將下劃線作為保留字段,我們強烈建議使用java標準的命名規則。
特殊參數的處理
為了在查詢中處理參數,你可以按照上面例子中的那樣,簡單的定義方法參數。除了這些之外,它還可以認識特殊的類型如:Pageable和Sort,他們可以在查詢中應用分頁和排序。例子如下:
Page<User> findByLastname(String lastname, Pageable pageable); Slice<User> findByLastname(String lastname, Pageable pageable); List<User> findByLastname(String lastname, Sort sort); List<User> findByLastname(String lastname, Pageable pageable);第一個方法將通過Pageable實例在查詢中添加分頁,Page接口知道元素的總數和可用的分頁。它是通過底層觸發count方法進行總數查詢,這將會依賴數據庫的使用,我們可以使用Slice替換Page。Slice僅僅知道是否有下一個可用的Slice,這樣在遍歷大結果集是非常足夠的。
排序選項也可以通過Pageable實例處理,如果僅僅需要排序,你可以簡單在方法中加入Sort參數,返回的是一個簡單List。為了找到你的查詢有多少頁,你必須觸發一個額外的count查詢,默認的,這個查詢是從你觸發的那個查詢衍生出來的。
限制查詢結果
查詢方法的結果可以被關鍵字限制,如:first,top,它們可以被交換使用。后面跟隨的數值將制定最大的結果集,如果數字沒有設置,將返回一個結果。
用Top和First限制查詢結果大小
User findFirstByOrderByLastnameAsc(); User findTopByOrderByAgeDesc(); Page<User> queryFirst10ByLastname(String lastname, Pageable pageable); Slice<User> findTop3ByLastname(String lastname, Pageable pageable); List<User> findFirst10ByLastname(String lastname, Sort sort); List<User> findTop10ByLastname(String lastname, Pageable pageable);限制的表達式也支持Distinct關鍵字,限制查詢的結果集設置到一個實例中,將結果封裝到Optional中也是支持的。
如果pagination或者slicing應用到限制的查詢分頁中,他們也是在限制的結果集中應用。
查詢結果流
查詢的結果也可以用java8的Stream<T>處理,這樣可以使用stream的良好性能。
@Query("select u from User u") Stream<User> findAllByCustomQueryAndStream();Stream<User> readAllByFirstnameNotNull();@Query("select u from User u") Stream<User> streamAllPaged(Pageable pageable);由于stream使用了底層的資源,在使用后必須關閉,你可以使用close手動關閉,也可以使用java7的try-with-resources 塊。
try (Stream<User> stream = repository.findAllByCustomQueryAndStream()) { stream.forEach(…); }現在并不是所有的Spring Data模塊都支持Stream。
異步查詢結果
倉庫的查詢方法可以異步執行,這意味著查詢會提交到Spring TaskExecutor,并不會立即執行。
@Async Future<User> findByFirstname(String firstname); @Async CompletableFuture<User> findOneByFirstname(String firstname); @Async ListenableFuture<User> findOneByLastname(String lastname);第一個方法使用Future作為返回結果。
第二個方法使用java8的CompletableFuture作為返回結果。
第三個方法使用了Spring的ListenableFuture作為返回結果。
生成倉庫實例
每一個Spring Data模塊都包含一個repositories元素指定Spring 掃描的包路徑。
Spring Data的xml配置方式
<?xml version="1.0" encoding="UTF-8"?> <beans:beans xmlns:beans="http://www.springframework.org/schema/beans"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xmlns="http://www.springframework.org/schema/data/jpa"xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/data/jpa http://www.springframework.org/schema/data/jpa/spring-jpa.xsd"><repositories base-package="com.acme.repositories" /> </beans:beans>在上面的例子中,Spring掃描com.acme.repositories和它所有子包中,所有繼承了Repository和它子類的所有幾口,并將它們構造成倉庫。每一個接口被發現,spring都將注冊指定的持久化技術并生成合適的代理處理查詢方法。每一個bean都是通過接口的名字注冊而成,所以UserRepository接口將會注冊成userRepository。base-package參數可以使用正則表達式。
使用JavaConfig注解的方式也可以配置包的掃描
@Configuration @EnableJpaRepositories("com.acme.repositories") class ApplicationConfiguration {@BeanEntityManagerFactory entityManagerFactory() { // … } }在這里,我們使用Jpa作為例子。
Spring Data的Common模塊就介紹到這里,歡迎大家在評論區多多交流
總結
以上是生活随笔為你收集整理的Spring Data(二)查询的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 盘点Kubernetes网络问题的4种解
- 下一篇: 1-javascript基础学习