1. 概述
在本教程中,我们将介绍 Hibernate Object/Grid Mapper (OGM) 的基本用法。
Hibernate OGM 是一个为 NoSQL 数据存储提供 JPA(Java Persistence API)支持 的框架。NoSQL 是一类非关系型数据存储的统称,包括键值存储、文档存储、列式存储以及图数据库等。
⚠️ 注意:Hibernate OGM 目前已不再积极开发和支持。最后一次更新是在 2018 年,社区也没有继续维护的计划。
2. Hibernate OGM 架构
Hibernate 传统上是为关系型数据库提供 ORM(对象关系映射)功能。而 Hibernate OGM 扩展了这一能力,使其能够支持 NoSQL 数据存储系统。使用它的最大优势在于,我们可以在关系型数据库和 NoSQL 数据库之间保持一致的 JPA 接口体验。
Hibernate OGM 能够支持多种 NoSQL 数据库,主要依赖于两个核心接口:DatastoreProvider
和 GridDialect
。每当支持一个新的 NoSQL 数据库时,都需要实现这两个接口。
✅ 当前 Hibernate OGM 支持的主流 NoSQL 数据库包括:
- 键值存储:Infinispan、Ehcache
- 文档存储:MongoDB、CouchDB
- 图数据库:Neo4j
此外,它还 完全支持事务,可以与标准的 JTA 提供者配合使用:
- 在 Jakarta EE 容器中无需额外配置即可使用
- 在 Java SE 环境下,可以使用 Narayana 等独立的 JTA 事务管理器
3. 环境搭建
在本教程中,我们使用 Maven 来管理依赖,并以 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>
说明:
hibernate-ogm-mongodb
:MongoDB 的 Hibernate OGM 方言支持narayana-jta
:提供 JTA 事务支持的 Narayana 事务管理器
3.2. 配置 Persistence Unit
在 persistence.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"
:指定使用 JTA 事务类型provider
:使用 Hibernate OGM 的持久化提供者hibernate.ogm.datastore.provider
:指定 MongoDB 为数据存储hibernate.ogm.datastore.database
:数据库名称hibernate.ogm.datastore.create_database
:自动创建数据库
📌 默认假设 MongoDB 已运行在本地默认端口。若非如此,可参考 官方文档 或 这篇文章 进行配置。
4. 实体定义
定义实体类的方式与使用 Hibernate ORM 或 JPA 完全一致。这是 Hibernate OGM 的核心承诺:使用标准 JPA 注解,即可无缝切换到 NoSQL 数据库。
本例中的领域模型如下:
实体类定义如下:
@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
:标识为实体类@Id
+@GeneratedValue
:主键 + UUID 生成策略@OneToMany
/@ManyToOne
:建立实体间的双向关联
5. 数据操作
实体定义完成后,我们就可以使用标准 JPA API 进行数据操作。
首先,我们创建一些测试数据,比如一个 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();
}
接着,我们可以加载刚刚保存的数据并验证:
@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();
// 其他断言验证实体和关系
}
✅ 重点在于:我们完全使用标准 JPA 接口,无需关心底层是 MongoDB 还是传统关系型数据库。
6. 切换后端数据库
Hibernate OGM 的一大亮点是后端可切换。我们来试试将 MongoDB 换成 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:
<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 配置项请参考 官方文档。
✅ 最终效果:我们从 MongoDB(文档型)切换到 Neo4j(图型),但业务代码完全不用改动,这就是 Hibernate OGM 的魅力所在。
7. 总结
本文介绍了 Hibernate OGM 的核心概念与使用方式,包括架构原理、实体定义、数据操作以及后端切换。
虽然 Hibernate OGM 已停止维护,但在一些遗留系统或需要快速适配多种 NoSQL 数据库的场景中,仍有一定的参考价值。
📝 示例代码已上传至 GitHub。