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 数据库,主要依赖于两个核心接口:DatastoreProviderGridDialect。每当支持一个新的 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 数据库

本例中的领域模型如下:

Domain Model

实体类定义如下:

@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


原始标题:A Guide to Hibernate OGM