数据库 ogm_带有Hibernate OGM的NoSQL –第二部分:查询数据
數據庫 ogm
Hibernate OGM的第一個最終版本發布于 1月底,團隊一直在忙于制作一系列教程式博客,使您有機會輕松地從Hibernate OGM重新開始。 第一部分是關于設置和保留您的第一個實體 。 在第二部分中,您將學習如何查詢數據。 Hibernate OGM將使您以幾種不同的方式獲取數據:
- 使用Java持久性查詢語言(JP-QL)
- 使用您選擇的數據存儲的NoSQL本機查詢語言(如果有的話)
- 使用Hibernate Search查詢–主要是全文查詢
所有這些替代方案將使您可以在數據存儲上運行查詢,并以托管實體列表的形式獲取結果。
準備測試課
我們將添加一個新的類HikeQueryTest。 它將使用有關加息的一些信息填充數據存儲區:
public class HikeQueryTest {private static EntityManagerFactory entityManagerFactory;@BeforeClasspublic static void setUpEntityManagerFactoryAndPopulateTheDatastore() {entityManagerFactory = Persistence.createEntityManagerFactory( "hikePu" );EntityManager entityManager = entityManagerFactory.createEntityManager();entityManager.getTransaction().begin();// create a PersonPerson bob = new Person( "Bob", "McRobb" );// and two hikesHike cornwall = new Hike("Visiting Land's End", new Date(), new BigDecimal( "5.5" ),new HikeSection( "Penzance", "Mousehole" ),new HikeSection( "Mousehole", "St. Levan" ),new HikeSection( "St. Levan", "Land's End" ));Hike isleOfWight = new Hike("Exploring Carisbrooke Castle", new Date(), new BigDecimal( "7.5" ),new HikeSection( "Freshwater", "Calbourne" ),new HikeSection( "Calbourne", "Carisbrooke Castle" ));// let Bob organize the two hikescornwall.setOrganizer( bob );bob.getOrganizedHikes().add( cornwall );isleOfWight.setOrganizer( bob );bob.getOrganizedHikes().add( isleOfWight );// persist organizer (will be cascaded to hikes)entityManager.persist( bob );entityManager.getTransaction().commit();entityManager.close();}@AfterClasspublic static void closeEntityManagerFactory() {entityManagerFactory.close();} }此方法將確保在運行測試之前已創建實體管理器工廠,并且數據存儲區包含一些數據。 這些數據與我們在第1部分中存儲的數據相同。
現在我們已經有了一些數據,我們可以開始編寫一些測試來搜索它們。
使用Java持久性查詢語言(JP-QL)
JP-QL是一種查詢語言,被定義為Java Persistence API(JPA)規范的一部分 。 它旨在與實體一起使用并且獨立于數據庫。
以實體遠足為例:
@Entity public class Hike {@Id@GeneratedValue(generator = "uuid")@GenericGenerator(name = "uuid", strategy = "uuid2")private String id;private String description;private Date date;private BigDecimal difficulty;@ManyToOneprivate Person organizer;@ElementCollection@OrderColumn(name = "sectionNo")private List<HikeSection> sections;// constructors, getters, setters, ... }JP-QL查詢可獲取按難度排序的可用加息列表,如下所示:
SELECT h FROM Hike h ORDER BY h.difficulty ASCHibernate OGM將解析此查詢,并將其轉換為您選擇的數據存儲區的本機查詢語言中的等效查詢。 例如,在Neo4j中,它創建并執行如下所示的Cypher查詢:
MATCH (h:Hike) RETURN h ORDER BY h.difficulty在MongoDB中,使用MongoDB JavaScript API作為查詢符號,它看起來像這樣:
db.Hike.find({}, { "difficulty": 1})如果在應用程序中使用JP-QL,則無需更新查詢就可以在數據存儲區之間切換。
現在您已經了解了所發生的情況,我們可以開始查詢持久化的數據。 例如,我們可以獲取可用加息的列表:
@Testpublic void canSearchUsingJPQLQuery() {// Get a new entityManagerEntityManager entityManager = entityManagerFactory.createEntityManager();// Start transactionentityManager.getTransaction().begin();// Find all the available hikes ordered by difficultyList<Hike> hikes = entityManager.createQuery( "SELECT h FROM Hike h ORDER BY h.difficulty ASC" , Hike.class ).getResultList();assertThat( hikes.size() ).isEqualTo( 2 );assertThat( hikes ).onProperty( "description" ).containsExactly( "Visiting Land's End", "Exploring Carisbrooke Castle" );entityManager.getTransaction().commit();entityManager.close();}如果您曾經使用過JPA規范,就會發現此代碼非常熟悉:這與使用JPA處理關系數據庫時所編寫的代碼相同。
您可以通過在Neo4j和MongoDB之間切換配置和依賴項來進行測試:測試仍將通過而無需更改代碼。
很棒的事情是,您可以對沒有自己的查詢引擎的數據存儲使用JP-QL查詢。 在這種情況下,Hibernate OGM的查詢解析器將創建全文查詢,這些查詢通過Hibernate Search和Lucene執行。 稍后我們將詳細介紹如何執行此操作。
查詢的結果是被管理實體的列表。 這意味著對對象的更改將自動應用于數據庫中的數據。 您還可以瀏覽結果對象圖,從而根據需要加載惰性關聯。
JP-QL語言的支持不完整,并且可能會因后端而異。 我們將把細節留給Hibernate OGM的官方文檔。 目前支持的是:
- 簡單比較
- IS NULL和IS NOT NULL
- 布爾運算符AND , OR , NOT
- LIKE,IN和BETWEEN
- 訂購
如果JP-QL不適用于您的用例,我們將了解如何使用所選后端的本機語言執行查詢。
使用本機后端查詢語言
有時,您可能決定犧牲可移植性,而使用基礎本機查詢語言的功能。 例如,您可能想從Neo4j的Cypher語言的功能中受益,以運行分層/遞歸查詢。 使用MongoDB,讓我們通過“ Penzance”進行加息:
// Search for the hikes with a section that start from "Penzace" in MongoDB List<Hike> hikes = entityManager.createNativeQuery("{ $query : { sections : { $elemMatch : { start: 'Penzance' } } } }", Hike.class ).getResultList();Neo4j的相同代碼如下所示:
// Search for the hikes with a section that start from "Penzace" in Neo4j List<Hike> hikes = entityManager.createNativeQuery( "MATCH (h:Hike) -- (:Hike_sections {start: 'Penzance'} ) RETURN h", Hike.class ).getResultList();需要注意的重要一點是,與JPA查詢一樣,查詢返回的對象是托管實體。
您還可以使用注釋javax.persistence.NamedNativeQuery定義查詢:
@Entity @NamedNativeQuery( name = "PenzanceHikes", query = "{ $query : { sections : { $elemMatch : { start: 'Penzance' } } } }", resultClass = Hike.class ) public class Hike { ... }然后像這樣執行它:
List<Hike> hikes = entityManager.createNamedQuery( "PenzanceHikes" ).getResultList();使用Hibernate Search查詢
Hibernate Search提供了一種將Java對象索引到Lucene索引中并對其執行全文查詢的方法。 索引確實位于數據存儲區之外。 這意味著即使本機不支持查詢功能,也可以具有查詢功能。 它還在功能集和可伸縮性方面提供了一些有趣的屬性。 特別是,使用Hibernate Search,您可以減輕查詢執行的負擔,以分離節點并獨立于實際的數據存儲節點擴展其規模。
在此示例中,我們將使用MongoDB。 您首先需要將Hibernate Search添加到您的應用程序。 在Maven項目中,您需要在pom.xml中添加以下依賴項:
<dependencies>...<dependency><groupId>org.hibernate</groupId><artifactId>hibernate-search-orm</artifactId></dependency>... </dependencies>現在,您可以選擇要索引的內容:
@Entity @Indexed public class Hike {@Id@GeneratedValue(generator = "uuid")@GenericGenerator(name = "uuid", strategy = "uuid2")private String id;@Fieldprivate String description;private Date date;private BigDecimal difficulty;@ManyToOneprivate Person organizer;@ElementCollection@OrderColumn(name = "sectionNo")private List<HikeSection> sections;// constructors, getters, setters, ... }@Indexed批注標識我們要索引的類,而@Field批注指定我們要索引的類的屬性。 每當使用Hibernate OGM通過實體管理器保留新的Hike實體時,Hibernate Search都會自動將其添加到索引中并跟蹤對托管實體的更改。 這樣,索引和數據存儲就可以保持最新狀態。
現在,您可以使用Lucene查詢來尋找Carisbrooke的遠足。 在此示例中,我們將使用Hibernate Search提供的查詢構建器:
@Test public void canSearchUsingFullTextQuery() {EntityManager entityManager = entityManagerFactory.createEntityManager();entityManager.getTransaction().begin();//Add full-text superpowers to any EntityManager:FullTextEntityManager ftem = Search.getFullTextEntityManager(entityManager);// Optionally use the QueryBuilder to simplify Query definition:QueryBuilder b = ftem.getSearchFactory().buildQueryBuilder().forEntity( Hike.class ).get();// A Lucene query to search for hikes to the Carisbrooke castle:Query lq = b.keyword().onField("description").matching("Carisbrooke castle").createQuery();//Transform the Lucene Query in a JPA Query:FullTextQuery ftQuery = ftem.createFullTextQuery(lq, Hike.class);//This is a requirement when using Hibernate OGM instead of ORM:ftQuery.initializeObjectsWith( ObjectLookupMethod.SKIP, DatabaseRetrievalMethod.FIND_BY_ID );// List matching hikesList<Hike> hikes = ftQuery.getResultList();assertThat( hikes ).onProperty( "description" ).containsOnly( "Exploring Carisbrooke Castle" );entityManager.getTransaction().commit();entityManager.close(); }代碼的結果將是描述中提到“ Carisbrooke城堡”的遠足清單。
Hibernate Search是一個非常強大的工具,具有許多不同的選項,在本教程中描述所有這些選項都將花費很長時間。 您可以查看參考文檔以了解更多信息。
結語
目前為止就這樣了。 如您所見,Hibernate OGM為您提供了一系列選項來對數據存儲區運行查詢,這些選項應滿足您大多數典型的查詢需求:JP-QL,本機NoSQL查詢和通過Hibernate Search / Apache Lucene進行的全文查詢。 即使您以前從未使用過NoSQL數據存儲區,也可以輕松地對其進行試驗。
您可以在GitHub上找到此博客文章(以及上一篇)的完整示例代碼 。 只需叉子,然后隨心所欲地玩就可以了。
既然您知道如何存儲和查找實體,我們將在本系列的下一部分中看到如何將所有內容放入應用程序容器(如WildFly)中 。
我們渴望了解您的意見,隨時發表評論或與我們聯系 ,我們將回答您的問題并聽到您的反饋。
感謝Gunnar Morling( @gunnarmorling )和Davide D'Alto(@Github: DavidD )創建了本教程。
翻譯自: https://www.javacodegeeks.com/2015/02/nosql-hibernate-ogm-part-two-querying-data.html
數據庫 ogm
總結
以上是生活随笔為你收集整理的数据库 ogm_带有Hibernate OGM的NoSQL –第二部分:查询数据的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 徐州的鮥鱼是什么鱼 徐州的鮥鱼介绍
- 下一篇: osgi:install_OSGi服务测