Spring Data 4.4-4.5翻譯
4.4定義查詢方法
倉庫代理有兩種通過函數名的方式去獲得stored-specific的查詢方法。它可以通過直接使用定義好的方法名或者通過自己手動定義的方法名來調用查詢。可提供的選項依賴於實際場景。然而,以下策略是在使用過程中需要考慮的。
4.4.1查詢查找的策略
以下策略是供倉庫的架構去解決這種查詢。你可以通過在xml文件裏配置query-lookup-strategy屬性,或者可以在java的配置文件裏通過${}賦值給QueryLookupSTrategy屬性。實際上這些策略並不支持有些數據存儲。
CREATE試圖通過方法名稱去構建一個stored-specific的查詢方法。通用的方式是把大家所熟悉的前綴去掉,解析剩下部分的方法名。更多關於創建查詢的內容請查看鏈接。
USE_DECLARED_QUERY 嚐試去查找一個聲明的方法,如果木有找到,則會拋出沒有找到方法的異常。可以通過在某處定義方法或者聲明來使用。可以通過翻閱存儲文檔去找到合適的存儲選項。如果倉庫的架構在程序引導時間內沒有找到聲明的方法,查找失敗。
CREATE_IF_NOT_FOUND(默認) 包含了CREATE和USE_DECLARED_QUERY。它會先查找聲明的查找,如果沒有找到聲明的查找,它將會創建一個定製的基於名字的查詢方法。這是默認的查找策略並且將會被使用當你沒有明確的配置方法的時候。它允許通過名稱快速的定義查詢,也可以有需要的通過引入聲明的查詢方法來自定義這些查詢
4.4.2創建查詢
查詢構造器構建Spring Data倉庫架構的機製作用於在倉庫實體下構建強約束。這種機製會拆解方法裏包含的find…BY。。。,然後會解析剩餘的部分。引入的選項包含更多的表達式,類似於一個用於在被創建的查詢裏設置明顯的標誌的Distinct。然而,第一個出現的By作為一個分隔符去表明真實標準的開始。基礎階段,你可以通過定義實體的條件並使用And和Or把條件聯合起來。
Example 11. 從方法名中創建查詢
public interface PersonRepository extends Repository<User, Long> { List<Person> findByEmailAddressAndLastname(EmailAddress emailAddress, String lastname); // Enables the distinct flag for the query List<Person> findDistinctPeopleByLastnameOrFirstname(String lastname, String firstname); List<Person> findPeopleDistinctByLastnameOrFirstname(String lastname, String firstname); // Enabling ignoring case for an individual property List<Person> findByLastnameIgnoreCase(String lastname); // Enabling ignoring case for all suitable properties List<Person> findByLastnameAndFirstnameAllIgnoreCase(String lastname, String firstname); // Enabling static ORDER BY for a query List<Person> findByLastnameOrderByFirstnameAsc(String lastname); List<Person> findByLastnameOrderByFirstnameDesc(String lastname); }
實際解析方法的結果取決於你創建的查詢的持久性的存儲。無論如何,以下幾點值得注意: 表達式的屬性遍曆通常是由可以聯結的操作符組成的。你可以通過AND和OR來聯結屬性表達式。你也可以獲得類似於Between…等的操作符的支持。支持的操作符因數據庫而異,所以請查閱合適的章節。 方法解析器支持為個人特性設置一個IgnoreCase標誌(類似於。。。),或者為一種支持忽略特性的類型的所有的屬性(通常是String類型,類型於。。。)。忽略特性是否被支持取決於不同的存儲。所以請查閱合適的章節。 你可以通過添加一個OrderBy條件到涉及到屬性和提供了分類方向(Asc或者Desc)方法查詢裏。如何創建一個可以支持動態排序的查詢方法,請查看。。。
4.4.3屬性表達式
屬性表達式僅僅隻能應用於托管屬性上,先前的例子中有說明。你應該在創建查詢期間確認你所解析的屬性是托管域的類所包含的字段。無論如何,你也能通過串聯多個嵌套的屬性來定義約束。例如一個Person擁有一個Address,Address也對應著一個ZipCode。在這種情況下一個方法名類似於
List<Person> findByAddressZipCode(ZipCode zipCode); 會創建屬性串聯x.address.ZipCode。這分解算法通過解析整一部分的(AddressZipCode)作為屬性並且用屬性名去查找映射類中的屬性(以小寫模式)。如果匹配將會使用該屬性。不然,這個算法會按照駝峰法來分割它,把該屬性分割為頭部分和尾部分,在我們的例子裏會分割成AddressZip和Code屬性。若沒有匹配的話將會通過建樹的方式left(AddressZip,Cod),並繼續在其左子樹裏查詢。 盡管大多數情況,這將會得到解決。但這依然有可能會選擇錯誤的屬性。假設Person類裏麵存在addressZip屬性。這個算法會首先匹配已經存在的屬性,這就導致了查詢失敗。(因為addressZip屬性可能沒有Code屬性)。 要解決這個問題,建議使用_去手動定義分割點。
List<Person> findByAddress_ZipCode(ZipCode zipCode);
由於我們認為下劃線是我們的保留符號。我們強烈建議去跟隨java的命名規則(使用駝峰法而不是下劃線)。
4.4.4特殊參數處理
你隻需要按照上文說的簡單的定義你的方法參數,你就能在查詢裏處理你的參數了。此外,這個架構能夠識別特定的類型,像Pageable和Sort,並應用於分頁和查詢時的動態排序。
Example 12. 在方法裏使用分頁,切片和排序 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);
第一個方法允許你把org.springframework.data.domain.Pageable實例傳到查詢方法裏來動態的為你的靜態定義的方法增加排序。Page參數知道元素的總數和頁數。它是通過架構觸發一個計算查詢的方法去計算總數目。因為這個將會大大的依賴於存儲使用的情況。Slice(切片)可以被用來作為return的代替。當處理一個巨大的結果集的時候,一個Slice隻知道是否有下一個可以滿足的Slice可用。
排序選項也通過Pageable實例處理。 如果隻需要排序,隻需向您的方法添加一個org.springframework.data.domain.Sort參數。 你也可以看到,簡單地返回一個List也是可能的。 在這種情況下,將不會創建構建實際頁麵實例所需的附加元數據(這反過來意味著附加計數查詢將不會發生),而是簡單地在給定的實體範圍內限製查詢。
要找出所有通過查詢得到的頁數,你必須觸發一個額外的計數方法來實現。默認情況下,這個查詢是由你實際觸發的方法裏派生出來的。
4.4.5限製查詢集
查詢方法的結果可以通過關鍵字first或top來限製,它們可以互換使用。 通過把數字追加到top / first,來指定要返回的最大結果。 如果省略該數字,則假定結果大小為1。
Example 13. 使用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。
如果將分頁或切片應用於限製查詢分頁(以及可用頁麵的計算),那麼它也會會被應用於限製結果集上。
4.4.6流查詢集
通過使用Java 8 Stream <T>來遞增地處理查詢方法的結果作為返回類型。這不是簡單地將查詢結果包裝成流數據的存儲,而是使用特定方法來處理流傳輸。
Example 14. 使用Java 8 Stream<T>的流查詢
@Query("select u from User u") Stream<User> findAllByCustomQueryAndStream(); Stream<User> readAllByFirstnameNotNull(); @Query("select u from User u") Stream<User> streamAllPaged(Pageable pageable); 流可能會封裝基礎數據來存儲特定資源,因此必須在使用後關閉。您可以使用close()方法或使用Java 7 try-with-resources塊手動關閉流。
Example 15. 在try-with-resources塊使用Stream<T>作為返回結果
try (Stream<User> stream = repository.findAllByCustomQueryAndStream()) { stream.forEach(…); }
不是所有的Spring Data模塊支持Stream<T>作為返回結果。
4.4.7異步查詢結果
通過使用Spring的異步方法功能可以異步地執行存儲庫查詢。這意味著該方法將在調用時立即返回,並且實際的查詢過程將發生在已經提交到Spring任務執行器的任務裏。
@Async Future<User> findByFirstname(String firstname); @Async CompletableFuture<User> findOneByFirstname(String firstname); @Async ListenableFuture<User> findOneByLastname(String lastname);
- 使用 java.util.concurrent.Future 作為返回類型。
- 使用 Java 8 java.util.concurrent.CompletableFuture 作為返回類型。
- 使用 org.springframework.util.concurrent.ListenableFuture 作為返回類型。
4.5創建存儲庫實例
在本節中,您為定義的存儲庫接口創建實例和bean定義。一種方法是使用每個支持存儲庫機製的Spring Data模塊附帶的Spring命名空間,盡管我們通常建議使用Java-Config樣式配置。
4.5.1XML配置
每個Spring Data模塊都包含一個repository元素,它允許您簡單地定義一個被Spring掃描的基礎包。
Example 16. 通過XML配置Spring Data的倉庫
<?xml version="1.0" encoding="UTF-8"?> <beans:beans xmlns:beans="https://www.springframework.org/schema/beans" xmlns:xsi="https://www.w3.org/2001/XMLSchema-instance" xmlns="https://www.springframework.org/schema/data/jpa" xsi:schemaLocation="https://www.springframework.org/schema/beans https://www.springframework.org/schema/beans/spring-beans.xsd https://www.springframework.org/schema/data/jpa https://www.springframework.org/schema/data/jpa/spring-jpa.xsd">
<repositories base-package="com.acme.repositories" />
</beans:beans>
在前麵的例子裏,Spring被指定去掃描com.acme.repositories及其所有子包去查找擴展Repository或其子接口之一。對於找到的每個接口,架構通過注冊持久性的特定的FactoryBean來創建處理查詢方法的調用的適當代理。 每個bean都注冊在從接口名稱派生的bean名稱下,因此UserRepository的接口將注冊在userRepository下。 base-package屬性允許使用通配符,所以你可以自定義掃描包的模式。
使用過濾器
默認情況下,架構會在配置的基礎包下挑選所有繼承了持久性的特定的Repository子接口的每個接口,並為其創建一個bean實例。但是,您可能希望更精細的控製哪些接口bean實例獲取創建。為此,您需要在<repositories />中使用<include-filter />和<exclude-filter />元素。語義完全等同於Spring的上下文命名空間中的元素。 有關詳細信息,請參閱有關這些元素的Spring參考文檔。
例如,你可以使用以下的配置從實例裏麵去排除特定的接口,來構建倉庫。
Example 17. 使用過濾器元素 <repositories base-package="com.acme.repositories"> <context:exclude-filter type="regex" expression=".*SomeRepository" /> </repositories>
這個例子過濾了所有被實例化後以SomeRepository結尾的接口。
4.5.2Java配置
還可以通過JavaConfig類上的存儲庫裏特有的@ Enable $ {store} Repositories聲明來觸發存儲庫架構。有關Spring容器的基於Java的配置的介紹,請參閱參考文檔。
啟用Spring Data存儲庫的示例配置如下所示。
Example 18. 基於倉庫配置的聲明樣例 @Configuration @EnableJpaRepositories("com.acme.repositories") class ApplicationConfiguration {
@Bean public EntityManagerFactory entityManagerFactory() { // … } } 該示例使用JPA特定的注釋,您可以根據實際使用的存儲模塊更改它。 這同樣適用於EntityManagerFactory bean的定義。 請參閱涵蓋商店特定配置的部分。
4.5.3獨立使用
您還可以使用Spring容器之外的存儲庫基礎結構,例如 在CDI環境中。 你仍然需要在classpath中有一些Spring類庫包,但是通常你也可以用編程方式設置存儲庫。提供存儲庫支持的Spring Data模塊提供了一個持久性倉庫特有的RepositoryFactory的倉庫,您可以使用如下。
Example 19. 倉庫工廠的獨立使用 RepositoryFactorySupport factory = … // Instantiate factory here UserRepository repository = factory.getRepository(UserRepository.class);
最後更新:2017-05-19 11:31:47