Hibernate OGM指南
1. 概述
在本教程中,我们将介绍Hibernate Object/Grid Mapper (OGM) 的基础知识。 Hibernate OGM 为 NoSQL 数据存储提供 Java Persistence API (JPA) 支持。NoSQL 是一个涵盖各种数据存储的总称。例如,这包括键值、文档、面向列和面向图形的数据存储。
2. Hibernate OGM 的架构
Hibernate 传统上为关系数据库提供对象关系映射 (ORM) 引擎。Hibernate OGM 引擎扩展了其功能以支持 NoSQL 数据存储。 使用它的主要好处是 JPA 接口在关系和 NoSQL 数据存储之间的一致性。
由于两个关键接口DatastoreProvider和GridDialect,Hibernate OGM 能够提供对许多 NoSQL 数据存储的抽象。因此,它支持的每个新 NoSQL 数据存储都带有这些接口的实现。
截至今天,它并不支持所有 NoSQL 数据存储,但它能够与其中的许多数据存储一起使用,例如 Infinispan 和 Ehcache(键值)、MongoDB 和 CouchDB(文档)以及 Neo4j(图形)。
**它还 完全支持事务 ,并且可以与标准 JTA 提供程序一起使用。**首先,这可以通过 Jakarta EE 容器提供,无需任何显式配置。此外,我们可以在 Java SE 环境中使用像 Narayana 这样的独立 JTA 事务管理器。
3. 设置
在本教程中,我们将使用 Maven 拉取所需的依赖项以使用 Hibernate OGM。我们还将使用MongoDB 。
为了澄清,让我们看看如何为教程设置它们。
3.1. Maven 依赖项
让我们看看使用 Hibernate OGM 和 MongoDB 所需的依赖项:
<dependency>
<groupId>org.hibernate.ogm</groupId>
<artifactId>hibernate-ogm-mongodb</artifactId>
<version>5.4.0.Final</version>
</dependency>
<dependency>
<groupId>org.jboss.narayana.jta</groupId>
<artifactId>narayana-jta</artifactId>
<version>5.9.2.Final</version>
</dependency>
在这里,我们通过 Maven 拉取所需的依赖项:
- MongoDB 的休眠 OGM 方言
- Narayana 事务管理器 (JTA 的实际提供者)
3.2. 持久性单元
我们还必须在 Hibernate persistance.xml中定义数据存储详细信息:
<persistence-unit name="ogm-mongodb" transaction-type="JTA">
<provider>org.hibernate.ogm.jpa.HibernateOgmPersistence</provider>
<properties>
<property name="hibernate.ogm.datastore.provider" value="MONGODB" />
<property name="hibernate.ogm.datastore.database" value="TestDB" />
<property name="hibernate.ogm.datastore.create_database" value="true" />
</properties>
</persistence-unit>
请注意我们在此处提供的定义:
- 属性 transaction-type 的值为“JTA”(这意味着我们需要来自 EntityManagerFactory 的 JTA 实体管理器)
- 提供者,它是Hibernate OGM 的 HibernateOgmPersistence
- 与数据库相关的一些额外细节(这些通常在不同的数据源之间有所不同)
该配置假定 MongoDB 正在运行并可在默认情况下访问。如果不是这种情况,我们可以随时提供必要的详细信息 。我们之前的一篇文章还详细介绍了设置 MongoDB 。
4. 实体定义
现在我们已经了解了基础知识,让我们定义一些实体。如果我们之前使用过 Hibernate ORM 或 JPA,则无需再添加. 这是 Hibernate OGM 的基本前提。它承诺让我们只需要 JPA 的知识就可以使用不同的 NoSQL 数据存储。
在本教程中,我们将定义一个简单的对象模型:
它定义了 Article、Author和Editor 类以及它们之间的关系。
让我们也用 Java 定义它们:
@Entity
public class Article {
@Id
@GeneratedValue(generator = "uuid")
@GenericGenerator(name = "uuid", strategy = "uuid2")
private String articleId;
private String articleTitle;
@ManyToOne
private Author author;
// constructors, getters and setters...
}
@Entity
public class Author {
@Id
@GeneratedValue(generator = "uuid")
@GenericGenerator(name = "uuid", strategy = "uuid2")
private String authorId;
private String authorName;
@ManyToOne
private Editor editor;
@OneToMany(mappedBy = "author", cascade = CascadeType.PERSIST)
private Set<Article> authoredArticles = new HashSet<>();
// constructors, getters and setters...
}
@Entity
public class Editor {
@Id
@GeneratedValue(generator = "uuid")
@GenericGenerator(name = "uuid", strategy = "uuid2")
private String editorId;
private String editorName;
@OneToMany(mappedBy = "editor", cascade = CascadeType.PERSIST)
private Set<Author> assignedAuthors = new HashSet<>();
// constructors, getters and setters...
}
我们现在已经定义了实体类并使用 JPA 标准注解对它们进行了注解:
- @Entity将它们建立为 JPA 实体
- @Id为具有 UUID 的实体生成主键
- @OneToMany和*@ManyToOne*建立实体之间的双向关系
5. 操作
现在我们已经创建了实体,让我们看看是否可以对它们执行一些操作。作为第一步,我们必须生成一些测试数据。在这里,我们将创建一个Editor、一些Author和一些Article。我们还将建立他们的关系。
此后,在我们执行任何操作之前,我们需要一个 EntityManagerFactory 的实例。 我们可以使用它来创建EntityManager。除此之外,我们还需要创建TransactionManager来处理事务边界。
让我们看看如何使用这些来持久化和检索我们之前创建的实体:
private void persistTestData(EntityManagerFactory entityManagerFactory, Editor editor)
throws Exception {
TransactionManager transactionManager =
com.arjuna.ats.jta.TransactionManager.transactionManager();
transactionManager.begin();
EntityManager entityManager = entityManagerFactory.createEntityManager();
entityManager.persist(editor);
entityManager.close();
transactionManager.commit();
}
在这里,我们使用EntityManager来持久化根实体,它级联到它的所有关系。我们也在定义的事务边界内执行此操作。
现在我们已准备好加载我们刚刚持久化的实体并验证其内容。我们可以运行一个测试来验证这一点:
@Test
public void givenMongoDB_WhenEntitiesCreated_thenCanBeRetrieved() throws Exception {
EntityManagerFactory entityManagerFactory =
Persistence.createEntityManagerFactory("ogm-mongodb");
Editor editor = generateTestData();
persistTestData(entityManagerFactory, editor);
TransactionManager transactionManager =
com.arjuna.ats.jta.TransactionManager.transactionManager();
transactionManager.begin();
EntityManager entityManager = entityManagerFactory.createEntityManager();
Editor loadedEditor = entityManager.find(Editor.class, editor.getEditorId());
assertThat(loadedEditor).isNotNull();
// Other assertions to verify the entities and relations
}
在这里,我们再次使用EntityManager来查找数据并对其执行标准断言。当我们运行这个测试时,它会实例化数据存储、持久化实体、取回它们并进行验证。
同样,我们刚刚使用 JPA 来保存实体及其关系。同样,我们使用 JPA 来加载实体并且一切正常,即使我们的数据库选择是 MongoDB 而不是传统的关系数据库。
6. 切换后端
我们也可以切换我们的后端。现在让我们来看看这样做有多么困难。
我们将后端更改为Neo4j ,它恰好是一个流行的面向图形的数据存储。
首先,让我们为 Neo4j 添加 Maven 依赖项:
<dependency>
<groupId>org.hibernate.ogm</groupId>
<artifactId>hibernate-ogm-neo4j</artifactId>
<version>5.4.0.Final</version>
</dependency>
接下来,我们必须在 persistence.xml 中添加相关的持久性单元:
<persistence-unit name="ogm-neo4j" transaction-type="JTA">
<provider>org.hibernate.ogm.jpa.HibernateOgmPersistence</provider>
<properties>
<property name="hibernate.ogm.datastore.provider" value="NEO4J_EMBEDDED" />
<property name="hibernate.ogm.datastore.database" value="TestDB" />
<property name="hibernate.ogm.neo4j.database_path" value="target/test_data_dir" />
</properties>
</persistence-unit>
简而言之,这些是 Neo4j 所需的非常基本的配置。这可以根据需要进一步详细说明 。
嗯,这几乎就是需要做的事情。当我们使用 Neo4j 作为后端数据存储运行相同的测试时,它运行得非常无缝。
请注意,我们已经将后端从恰好是面向文档的数据存储的 MongoDB 切换到了面向图形的数据存储 Neo4j。我们做了这一切,只做了很少的改动,并且不需要对我们的任何操作进行任何更改。