《Spring Data實戰》——2.2 定義查詢方法
本節書摘來自異步社區《Spring Data實戰》一書中的第2章,第2.2節,作者: 【美】Mark Pollack , Oliver Gierke , Thomas Risberg , Jon Brisbin , Michael Hunger著,更多章節內容可以訪問雲棲社區“異步社區”公眾號查看
2.2 定義查詢方法
2.2.1 查找查詢的策略
剛才看到的接口隻聲明了一個簡單的查詢方法。聲明的方法會被基礎設施探測到並進行解析,最終衍生出與存儲相關的查詢。但是,隨著查詢變得更加複雜,方法名會變得很冗長,顯得很笨拙。對於更複雜的查詢,依靠方法解析器所支持的關鍵字就不夠了。因此,每種存儲模塊都提供了@Query注解,如示例2-8所示,它會接受存儲相關的查詢語言所支持的查詢字符串,從而允許查詢執行時進一步地定製化。
示例2-8 使用@Query注解手動定義查詢
在這裏,我們使用JPA作為例子並手動定義了一個查詢,當然這個查詢原本也是可以通過衍生得到的。
查詢甚至可以外部化配置到屬性文件中(它位於MATA-INF目錄下的$store-named- queries.properties文件中),在這裏$store是用於替換jpa、mongo以及neo4j等的占位符。key值必須要遵循$domainType.$methodName這樣的約定。因此,為了將我們已有的方法替換成外部配置的命名查詢,key將會是Customer.findByEmailAddress。如果是使用已命名查詢的話,那就不需要使用@Query注解了。
2.2.2 衍生查詢
如示例2-9所示,查詢衍生機製內置於Spring Data Repository的基礎設施之中,對基於Repository的實體來構建限製性的查詢很有用處。我們會從方法中截取findBy、readBy以及getBy前綴並解析剩餘的部分。一個基礎的用法是,基於實體的屬性來定義條件並使用And和Or將它們連接起來。
示例2-9 由方法名衍生查詢
解析的實際結果依賴於我們所使用的數據存儲。這裏也有一些需要注意的通用事項。表達式通常會是屬性的遍曆以及操作符,它們可以連接起來。如示例2-9所示的那樣,可以通過And以及Or來連接屬性表達式。除此之外,對於屬性表達式來說,還可以支持各種操作符,如Between、LessThan、GreaterThan以及Like。因為不同的數據存儲之間所支持的操作符有所區別,所以要看查閱每種存儲對應的章節。
屬性表達式
屬性表達式可以直接引用所管理實體的屬性(如示例2-9中所示)。在查詢創建的時候,我們已經確保所解析的屬性就是領域類的屬性。但是,依然可以遍曆嵌套的屬性來定義限製條件。在前麵我們可以看到,Customer的Address中具有ZipCode屬性。在這種情況下,如下這種方法名的查詢將會創建x.address.zipCode這樣的屬性遍曆。
這個方案的算法首先會將整體(AddressZipCode)作為一個屬性進行解析並檢查領域類中是否具有該名稱的屬性(第一個字母小寫)。如果它存在的話,就會使用該屬性。如果不存在,它會從右邊開始將源信息按照“駝峰”命名的規則將其拆分為頭部和尾部,然後嚐試查找對應的屬性(如AddressZip和Code)。如果按照這個頭部信息找到了屬性,那麼我們將會使用尾部的信息繼續往下構建樹形的信息。因為示例中,第一次的分割並不匹配,我們將分割點繼續左移(從“AddressZip、Code”移到“Address、ZipCode”)。
盡管這在大多數的場景下都是可行的,但是在一定情況下算法可能會選擇錯誤的屬性。假設Customer同時還有一個addressZip屬性。那麼我們的算法將會在第一次分割的時候就完成了匹配,這實際上選擇了錯誤的屬性,並且會導致最終的失敗(因為addressZip類型可能並沒有code屬性)。為了解決這種模棱兩可的問題,可以在方法名中使用下劃線(_)來手動定義遍曆點。所以,我們的方法名最終看起來是這樣的:
2.2.3 分頁和排序
如果查詢所返回的結果數量增長很明顯,那麼分塊訪問數據就很有意義了。為了做到這一點,Spring Data提供了可與Repository一起使用的分頁API。要讀取哪一塊數據的定義隱藏在Pageable接口及其實現PageRequest之中。得到的分頁數據存放在Page中,它不僅包含了數據本身,還包含了元信息,這些信息包括它是不是第一頁或最後一頁以及一共有多少頁等。為了計算這個元數據,除了初始的查詢外,我們需要觸發第二次查詢。
借助於Repository,我們要使用分頁功能時隻需添加一個Pageable方法參數即可。不像其他的參數那樣,這個參數是不與查詢綁定的,用來限製返回的結果集。一種可選的方案就是返回Page類型,它會對結果集進行限製,但是需要另外一次查詢來獲取元信息(如可用元素的總數)。另一種可選的方案是使用List,它會避免額外的查詢,但是不會提供元數據。如果不需要分頁功能,隻是想要排序,那麼可以給方法簽名上添加Sort參數,如示例2-10所示。
示例2-10 使用Pageable和Sort的查詢方法
第一個方法允許傳遞Pageable實例到查詢方法中,從而為靜態定義的查詢動態地增加分頁功能。排序的功能可以通過Sort參數顯式地傳遞給方法,也可以內嵌到PageRequest值對象中,如示例2-11所示。
示例2-11 使用Pageable和Sort
最後更新:2017-05-31 12:02:45