带有Hibernate OGM的NoSQL –第一部分:持久化您的第一个实体
Hibernate OGM的第一個最終版本已經發布 ,團隊從發布狂潮中恢復了一些。 因此,他們考慮建立一系列教程式博客,使您有機會輕松地從Hibernate OGM重新開始。 感謝Gunnar Morling( @gunnarmorling )創建了本教程。
介紹
不知道什么是Hibernate OGM? Hibernate OGM是Hibernate下的最新項目,它允許您通過著名的JPA將實體模型持久保存在不同的NoSQL存儲中。
我們將在接下來的幾周內介紹這些主題:
- 堅持您的第一個實體(此批次)
- 查詢數據
- 在WildFly上運行
- 在Java SE上使用CDI運行
- 將數據存儲到同一應用程序中的兩個不同存儲中
如果您希望我們討論其他主題,請告訴我們。 只需在下面添加評論或向我們發送您的建議 。
在本系列的第一部分中,我們將建立一個具有所需依賴項的Java項目,創建一些簡單實體,然后將它們寫入商店或從商店中讀取。 我們將從Neo4j圖形數據庫開始 ,然后僅需進行少量配置更改就切換到MongoDB文檔存儲 。
項目設置
首先讓我們創建一個具有所需依賴項的新Java項目。 在下面,我們將使用Maven作為構建工具,但是Gradle或其他工具當然可以很好地工作。
將其添加到pom.xml的dependencyManagement塊中:
... <dependencyManagement><dependencies>...<dependency><groupId>org.hibernate.ogm</groupId><artifactId>hibernate-ogm-bom</artifactId><type>pom</type><version>4.1.1.Final</version><scope>import</scope></dependency>...</dependencies> </dependencyManagement> ...這將確保您使用的是匹配版本的Hibernate OGM模塊及其依賴項。 然后將以下內容添加到dependencies塊:
... <dependencies>...<dependency><groupId>org.hibernate.ogm</groupId><artifactId>hibernate-ogm-neo4j</artifactId></dependency><dependency><groupId>org.jboss.jbossts</groupId><artifactId>jbossjta</artifactId></dependency>... </dependencies> ...依賴項是:
- Hibernate OGM模塊,用于處理嵌入式Neo4j數據庫; 這將引入所有其他必需的模塊,例如Hibernate OGM內核和Neo4j驅動程序。 使用MongoDB時,可以將其與hibernate-ogm-mongodb交換。
- JBoss對Java事務API(JTA)的實現,當不在WildFly之類的Java EE容器中運行時需要此實現
領域模型
我們的示例域模型由三個類組成: Hike , HikeSection和Person 。
之間存在組合關系Hike和HikeSection ,即上調包括幾個部分,其生命周期是完全依賴于遠足。 遠足部分列表已訂購; 堅持遠足及其部分時,必須保持此順序。
Hike與Person (充當遠足組織者)之間的關聯是雙向的多對一/一對多關系:一個人可以組織零個或多個遠足,而一個遠足恰好有一個人充當組織者。
映射實體
現在,通過創建實體類并用所需的元數據注釋它們來映射域模型。 讓我們從Person類開始:
@Entity public class Person {@Id@GeneratedValue(generator = "uuid")@GenericGenerator(name = "uuid", strategy = "uuid2")private long id;private String firstName;private String lastName;@OneToMany(mappedBy = "organizer", cascade = CascadeType.PERSIST)private Set<Hike> organizedHikes = new HashSet<>();// constructors, getters and setters... }實體類型使用@Entity注釋進行標記,而表示標識符的屬性則使用@Id注釋。
Hibernate OGM無需手動分配ID,而是提供了幾種ID生成策略,例如(模擬)序列,UUID等,因此可以解決這一問題。 通常,使用UUID生成器是一個不錯的選擇,因為它可以確保跨不同NoSQL數據存儲的可移植性,并使ID生成快速且可擴展。 但是根據您使用的商店,在MongoDB的情況下,您也可以使用特定的ID類型,例如對象ID(有關詳細信息,請參閱參考指南 )。
最后, @OneToMany將organizedHikes屬性標記為實體之間的關聯。 由于它是雙向實體,因此必須使用mappedBy屬性來指定負責管理它的關聯方。 指定級聯類型PERSIST可確保堅持一個人也將自動導致其關聯的遠足也得以堅持。
接下來是Hike類:
@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 and setters... }在這里, @ManyToOne批注標記了Hike和Organizer之間的雙向關聯的另一面。 由于HikeSection應該依賴于Hike,因此節列表通過@ElementCollection映射。 為了確保在數據存儲區中保持節的順序, @OrderColumn使用@OrderColumn 。 這將在保留的記錄中添加一個額外的“列”,其中包含每個部分的訂單號。
最后, HikeSection類:
@Embeddable public class HikeSection {private String start;private String end;// constructors, getters and setters... }與Person和Hike不同,它不是通過@Entity而是使用@Embeddable映射的。 這意味著它始終是另一個實體(在本例中為Hike )的一部分,因此也沒有自己的身份。 因此,它沒有聲明任何@Id屬性。
請注意,如果您一直在將Hibernate ORM與關系數據存儲一起使用,則這些映射看起來完全相同。 的確,這就是Hibernate OGM的承諾之一:盡可能簡化關系和NoSQL范例之間的遷移!
創建persistence.xml
有了實體類之后,JPA的persistence.xml描述符又丟失了一件事。 在src / main / resources / META-INF / persistence.xml下創建它:
<?xml version="1.0" encoding="utf-8"?><persistence xmlns="http://java.sun.com/xml/ns/persistence"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://java.sun.com/xml/ns/persistence http://java.sun.com/xml/ns/persistence/persistence_2_0.xsd"version="2.0"><persistence-unit name="hikePu" transaction-type="RESOURCE_LOCAL"><provider>org.hibernate.ogm.jpa.HibernateOgmPersistence</provider><properties><property name="hibernate.ogm.datastore.provider" value="neo4j_embedded" /><property name="hibernate.ogm.datastore.database" value="HikeDB" /><property name="hibernate.ogm.neo4j.database_path" value="target/test_data_dir" /></properties></persistence-unit> </persistence>如果您以前使用過JPA,那么您對持久性單元的定義應該非常熟悉。 與在關系數據庫之上使用經典Hibernate ORM的主要區別在于,我們需要為Hibernate OGM指定特定的提供程序類: org.hibernate.ogm.jpa.HibernateOgmPersistence 。
此外,還定義了一些特定于Hibernate OGM和所選后端的屬性來設置:
- 使用的后端(在這種情況下為嵌入式Neo4j圖形數據庫)
- Neo4j數據庫的名稱
- 存儲Neo4j數據庫文件的目錄
根據您的使用情況和后端,可能需要其他屬性,例如用于設置主機,用戶名,密碼等。您可以在名為<BACK END>Properties的類中找到所有可用的<BACK END>Properties ,例如Neo4jProperties , MongoDBProperties等。 。
保存和加載實體
有了所有這些位之后,就可以保留(并加載)某些實體。 為此創建一個簡單的JUnit測試外殼:
public class HikeTest {private static EntityManagerFactory entityManagerFactory;@BeforeClasspublic static void setUpEntityManagerFactory() {entityManagerFactory = Persistence.createEntityManagerFactory( "hikePu" );}@AfterClasspublic static void closeEntityManagerFactory() {entityManagerFactory.close();} }這兩種方法為persistence.xml中定義的持久性單元管理實體管理器工廠。 它保存在一個字段中,因此可以用于多種測試方法(請記住,實體管理器工廠創建起來相當昂貴,因此應將它們初始化一次并保留以備重復使用)。
然后創建一個持久保存并加載一些數據的測試方法:
@Test public void canPersistAndLoadPersonAndHikes() {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();// get a new EM to make sure data is actually retrieved from the store and not Hibernate's internal cacheentityManager.close();entityManager = entityManagerFactory.createEntityManager();// load it backentityManager.getTransaction().begin();Person loadedPerson = entityManager.find( Person.class, bob.getId() );assertThat( loadedPerson ).isNotNull();assertThat( loadedPerson.getFirstName() ).isEqualTo( "Bob" );assertThat( loadedPerson.getOrganizedHikes() ).onProperty( "description" ).containsOnly( "Visiting Land's End", "Exploring Carisbrooke Castle" );entityManager.getTransaction().commit();entityManager.close(); }注意這兩個動作在事務中如何發生。 Neo4j是一個完全事務性的數據存儲庫,可以通過JPA的事務處理API很好地控制它。 在實際的應用程序中,可能會使用一種較不冗長的方法進行事務控制。 根據所選的后端和應用程序運行的環境類型(例如Java EE容器,例如WildFly ),您可以利用通過CDI或EJB進行的聲明式事務管理。 但是,讓我們再保存一次。
保留了一些數據后,您可以使用Neo4j隨附的漂亮的Web控制臺對其進行檢查。 下面顯示了測試保留的實體:
Hibernate OGM旨在為您要定位的數據存儲提供最自然的映射。 對于Neo4j作為圖形數據存儲的情況,這意味著任何實體都將映射到相應的節點。
實體屬性被映射為節點屬性(請參見描述黑名單節點之一的黑框)。 任何不受本機支持的屬性類型都將根據需要進行轉換。 例如, date屬性就是這種情況,它以ISO格式的字符串形式保留。 此外,每個實體節點都具有標簽 ENTITY(以將其與其他類型的節點區分開)和用于指定其實體類型的標簽(在這種情況下為Hike)。
關聯被映射為節點之間的關系,關聯角色被映射為關系類型 。
請注意,Neo4j沒有嵌入式對象的概念。 因此,將HikeSection對象映射為帶有標簽EMBEDDED的節點,并與擁有的Hike節點鏈接。 節的順序通過關系上的屬性保留。
切換到MongoDB
Hibernate OGM的承諾之一是允許使用相同的API(即JPA)與不同的NoSQL存儲一起使用。 因此,讓我們看看MongoDB是如何保存和使用的,與Neo4j不同,MongoDB是一個文檔數據存儲區,并以類似JSON的表示形式保留數據。 為此,請首先將Neo4j后端替換為以下內容:
... <dependency><groupId>org.hibernate.ogm</groupId><artifactId>hibernate-ogm-mongodb</artifactId> </dependency> ... 然后使用可通過以下方式訪問的屬性更新persistence.xml中的配置,以將MongoDB作為后端使用
提供與您的環境匹配的主機名和憑據的MongoDBProperties (如果尚未安裝MongoDB,則可以在此處下載):
這就是將實體保留在MongoDB中而不是Neo4j中所需要做的全部工作。 如果現在再次運行測試,您將在數據存儲區中找到以下BSON文檔:
# Collection "Person" {"_id" : "50b62f9b-874f-4513-85aa-c2f59015a9d0","firstName" : "Bob","lastName" : "McRobb","organizedHikes" : ["a78d731f-eff0-41f5-88d6-951f0206ee67","32384eb4-717a-43dc-8c58-9aa4c4e505d1"] }# Collection Hike {"_id" : "a78d731f-eff0-41f5-88d6-951f0206ee67","date" : ISODate("2015-01-16T11:59:48.928Z"),"description" : "Visiting Land's End","difficulty" : "5.5","organizer_id" : "50b62f9b-874f-4513-85aa-c2f59015a9d0","sections" : [{"sectionNo" : 0,"start" : "Penzance","end" : "Mousehole"},{"sectionNo" : 1,"start" : "Mousehole","end" : "St. Levan"},{"sectionNo" : 2,"start" : "St. Levan","end" : "Land's End"}] } {"_id" : "32384eb4-717a-43dc-8c58-9aa4c4e505d1","date" : ISODate("2015-01-16T11:59:48.928Z"),"description" : "Exploring Carisbrooke Castle","difficulty" : "7.5","organizer_id" : "50b62f9b-874f-4513-85aa-c2f59015a9d0","sections" : [{"sectionNo" : 1,"start" : "Calbourne","end" : "Carisbrooke Castle"},{"sectionNo" : 0,"start" : "Freshwater","end" : "Calbourne"}] }同樣,映射是非常自然的,就像您在使用MongoDB這樣的文檔存儲時所期望的那樣。 通過在任一側存儲引用的ID,可以映射Person和Hike之間的雙向一對多/多對一關聯。 當加載回數據時,Hibernate OGM將解析ID,并允許將關聯從一個對象導航到另一個對象。
元素集合使用MongoDB的存儲分層結構的功能進行映射。 在此,加息的各個部分映射到擁有加息的文檔中的數組,并帶有附加的字段sectionNo來維護收集順序。 這樣可以通過一次往返數據存儲的方式非常有效地加載實體及其嵌入式元素。
包起來
在帶有Hibernate OGM 101的NoSQL的第一部分中,您學習了如何設置具有所需依賴項的項目,映射某些實體和關聯并將其持久化在Neo4j和MongoDB中。 所有這些都是通過眾所周知的JPA API進行的。 因此,如果您過去在關系數據庫之上使用過Hibernate ORM和JPA,那么深入NoSQL領域將變得異常簡單。
同時,每個商店都針對某些用例,因此提供了特定的功能和配置選項。 自然,這些不能通過通用API(例如JPA)公開。 因此,Hibernate OGM允許您使用本機NoSQL查詢,并允許通過其靈活的選項系統配置商店特定的設置。
您可以在GitHub上找到此博客文章的完整示例代碼 。 只需叉子,然后隨心所欲地玩就可以了。
當然,存儲實體并通過其ID取回它們僅僅是開始。 在任何實際的應用程序中,您都希望對數據運行查詢,并且您可能還想利用所選NoSQL存儲的某些特定功能和設置。 我們將在本系列的下一部分中談到這一點,請繼續關注!
翻譯自: https://www.javacodegeeks.com/2015/01/nosql-with-hibernate-ogm-part-one-persisting-your-first-entities.html
創作挑戰賽新人創作獎勵來咯,堅持創作打卡瓜分現金大獎總結
以上是生活随笔為你收集整理的带有Hibernate OGM的NoSQL –第一部分:持久化您的第一个实体的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 在WildFly 8.2中修补焊接3 –
- 下一篇: 路由器怎么改路由器绑定设备如何更换