对于 AI 代理:可在 https://www.mongodb.com/zh-cn/docs/llms.txt 获取文档索引—通过在任何 URL 路径后添加 .md 可获取所有页面的 Markdown 版本。

执行 CRUD 操作

在本指南中,您可以学习如何使用MongoDB Extension for Hibernate ORM 在MongoDB集合上运行创建、读取、更新和删除(CRUD)操作。

The examples in this guide use the Movie entity, which represents the sample_mflix.movies collection from the Atlas sample datasets. The Movie entity has the following definition:

import com.mongodb.hibernate.annotations.ObjectIdGenerator;import org.bson.types.ObjectId;import java.time.Instant;import java.util.List;import jakarta.persistence.Embedded; import jakarta.persistence.Entity;import jakarta.persistence.FetchType;import jakarta.persistence.Id;import jakarta.persistence.OneToMany;import jakarta.persistence.Table; @Entity@Table(name = "movies")public class Movie { @Id @ObjectIdGenerator private ObjectId id; private String title; private String plot; private int year; private List<String> cast; private List<String> directors; private Instant released; @Embedded private Awards awards; @OneToMany(mappedBy = "movie", fetch = FetchType.LAZY) private List<Comment> comments; public Movie(String title, String plot, int year, List<String> cast, List<String> directors, Instant released, Awards awards) { this.title = title; this.plot = plot; this.year = year; this.cast = cast; this.directors = directors; this.released = released; this.awards = awards; } public Movie() { } public ObjectId getId() { return id; } public String getTitle() { return title; } public void setTitle(String title) { this.title = title; } public String getPlot() { return plot; } public void setPlot(String plot) { this.plot = plot; } public int getYear() { return year; } public void setYear(int year) { this.year = year; } public List<String> getCast() { return cast; } public void setCast(List<String> cast) { this.cast = cast; } public List<String> getDirectors() { return directors; } public void setDirectors(List<String> directors) { this.directors = directors; } public Awards getAwards() { return awards; } public void setAwards(Awards awards) { this.awards = awards; } public Instant getReleased() { return released; } public void setReleased(Instant released) { this.released = released; } public List<Comment> getComments() { return comments; } public void setComments(List<Comment> comments) { this.comments = comments; }}

学习如何创建使用 MongoDB Extension for Hibernate ORM 与此 MongoDB 示例集合交互的 Java 应用程序,请参阅 入门 教程。

重要

持久性上下文

启用Hibernate ORM 能够与数据库交互,您必须使用 Hibernate Session 或 Jakarta Persistence EntityManager 在持久性上下文中运行操作。您还必须在事务中运行写入操作,才能修改MongoDB数据并保持数据完整性。

Before running the examples in this guide, ensure that you add persistence context and transaction management code to your application that resembles the following code:

var sf = HibernateUtil.getSessionFactory();Session session = sf.openSession();Transaction tx = session.beginTransaction(); // ... Perform CRUD operations here tx.commit();session.close();sf.close();

要使用会话,您必须创建一个配置 SessionFactory 的 HibernateUtil.java文件。要学习;了解更多信息,请参阅入门教程中的配置应用程序步骤。

通过将实体实例传递给以下方法来创建文档,这些方法会将相应的文档插入到集合中:

  • org.hibernate.Session.persist():使用 Hibernate API 将更改应用到数据库

  • jakarta.persistence.EntityManager.persist():使用 Jakarta Persistence API 将更改应用到数据库

提示

要学习;了解有关创建实体实例并将其持久保存到数据库的更多信息,请参阅 Hibernate ORM 用户指南中的持久化实体。

The following example creates a new Movie entity instance and uses the persist() method to insert a corresponding document into the sample_mflix.movies collection:

var myMovie = new Movie();myMovie.setTitle("Knives Out");myMovie.setYear(2019);myMovie.setCast(List.of("Ana de Armas", "Daniel Craig", "Chris Evans"));myMovie.setPlot("Detective Benoit Blanc investigates the mysterious death of crime novelist Harlan Thrombey, " + "unraveling lies as every Thrombey family member becomes a suspect.");session.persist(myMovie);

要从集合中检索文档,请将查询条件传递给 createQuery() 方法。以下 API 均提供 createQuery() 方法:

  • Hibernate 的 Session API:使用 Hibernate 查询语言 (HQL) 语法定义查询

  • Jakarta Persistence 的 EntityManager API:使用 Jakarta Persistence 查询语言 (JPQL) 语法(HQL 的子集)来定义查询

提示

要学习有关使用 HQL 和 JPQL 语法检索数据的更多信息,请参阅 Hibernate ORM 查询指南中的 Select 声明。

注意

本部分介绍如何使用 HQL 和 JPQL 读取文档,但您也可以使用构建者或原生查询来检索数据。要学习;了解详情,请参阅以下指南:

To retrieve only one document that matches your query criteria, chain the getSingleResult() method to the createQuery() method. The following example retrieves one document that has a title value of "Boyhood" from the sample_mflix.movies collection:

var singleResult = session.createQuery("from Movie where title = :t", Movie.class) .setParameter("t", "Boyhood") .getSingleResult();System.out.println("Title: " + singleResult.getTitle() + ", Year: " + singleResult.getYear());

提示

查询语法

要了解有关 HQL 和 JPQL 语法的更多信息,请参阅 Hibernate ORM 文档中的Hibernate 查询语言指南。

The following example calls the createQuery() method on a session to retrieve documents from the sample_mflix.movies collection. The code uses HQL and JPQL to return documents that have a year value of 1920 and prints their title values:

var results = session.createQuery("from Movie where year = :y", Movie.class) .setParameter("y", 1920) .getResultList();results.forEach(movie -> System.out.println(movie.getTitle()));

您可以执行以下操作来修改集合中的文档:

  • 更新一个文档:调用实体的 setter 方法来更改一个实体实例的字段值,然后使用会话或实体经理来保存更改。

  • 更新多个文档:将更新声明传递给会话或实体管理器上的 createQuery() 或 createMutationQuery() 方法。然后,调用 executeUpdate() 方法将更改应用到数据库。

提示

要学习;了解有关使用 Hibernate ORM 修改数据的更多信息,请参阅以下资源:

The following example retrieves a document by its ObjectId value. Then, the example calls the Movie entity's setTitle() method to update the document's title value to "Jurassic Park I":

// Your ObjectId value might differMovie movieById = session.get(Movie.class, new ObjectId("573a1399f29313caabcedc5d"));movieById.setTitle("Jurassic Park I");session.persist(movieById);

The following example updates the title value of matching documents from "The Three Stooges" to "The 3 Stooges". Then, the example calls the executeUpdate() method to apply the changes to the database:

var updateResult = session.createMutationQuery( "update Movie set title = :new where title = :old") .setParameter("new", "The 3 Stooges") .setParameter("old", "The Three Stooges") .executeUpdate();System.out.println("Number of movies updated: " + updateResult);

批量更新声明的 SET 子句也可以使用表达式,而不是字面值。表达式可以引用正在更新的字段或实体上的另一个字段。

以下示例使用算术表达式来增加 year 值为 "The 3 Stooges" 的文档的 title 值:

var updateResult = session.createMutationQuery( "update Movie m set m.year = m.year + 1 where m.title = :title") .setParameter("title", "The 3 Stooges") .executeUpdate();System.out.println("Number of movies updated: " + updateResult);

以下示例使用字段引用来设置 plot 值,以匹配 title 值,适用于 year 值为 1920 的文档:

var updateResult = session.createMutationQuery( "update Movie m set m.plot = m.title where m.year = :year") .setParameter("year", 1920) .executeUpdate();System.out.println("Number of movies updated: " + updateResult);

以下示例使用 CASE 表达式来设置 plot 值,具体取决于每个文档的 year 值是否在 2000 年之后。Hibernate ORM 扩展将 CASE 表达式转换为 MongoDB $switch 操作符,并使用 $set 管道阶段应用更新:

var updateResult = session.createMutationQuery( "update Movie m set m.plot = case when m.year > 2000 then 'Modern release' " + "else 'Classic release' end where m.title = :title") .setParameter("title", "The 3 Stooges") .executeUpdate();System.out.println("Number of movies updated: " + updateResult);

要了解有关 CASE 表达式的更多信息,请参阅“指定查询”指南中的条件逻辑的使用案例表达式部分。

更新或插入(upsert)操作会在存在匹配文档时更新文档,如果不存在匹配文档,则插入新文档。要执行更新或插入(upsert),请使用 upsert() 或 upsertMultiple() 方法。这些方法仅在 Hibernate 的 StatelessSession API 上可用。

注意

StatelessSession 实例不会追踪其检索到的实体的更改。要保存对实体的更改,请将其传递给另一个写入方法。将 StatelessSession 用于批量写入工作流。

Hibernate ORM 扩展会根据实体的标识符为更新或插入(upsert)操作创建过滤器,因此您的应用程序必须在调用 upsert() 之前分配标识符值。

即使您的实体使用 @ObjectIdGenerator 注解,upsert() 方法也不会生成标识符值。如果您未分配标识符值,Hibernate ORM 扩展将使用 null _id 值存储文档。

您可以使用 @Column(updatable = false) 注解来保护字段在更新或插入(upsert)操作期间不被更新。以下 Movie 实体定义使用 @Column(updatable = false) 注解 released 字段,这指示 Hibernate ORM 扩展在插入文档时写入该字段,但在更新现有文档时忽略该字段:

@Entity@Table(name = "movies")public class Movie { @Id @ObjectIdGenerator private ObjectId id; private String title; private int year; @Column(updatable = false) private Instant released; // Getters and setters omitted}

Hibernate ORM 扩展在生成的更新声明的 $set 操作符中发送可插入和可更新的字段。它在 $setOnInsert 操作符中发送只可插入的字段,例如使用 @Column(updatable = false) 注释的字段。

以下示例创建了一个 Movie 实体实例,并将其传递给 upsert() 方法。如果存在具有指定 ObjectId 值的文档,Hibernate ORM 扩展将更新该文档的 title 和 year 值。否则,Hibernate ORM 扩展将插入一个新文档:

try (StatelessSession statelessSession = sf.openStatelessSession()) { var movie = new Movie(); movie.setId(new ObjectId("573a1398f29313caabce9682")); movie.setTitle("The General"); movie.setYear(1926); movie.setReleased(Instant.parse("1927-02-24T00:00:00Z")); statelessSession.upsert(movie);}

要在一个操作中更新或插入(upsert)多个实体实例,请将实例列表传递给 upsertMultiple() 方法。以下示例更新或插入(upsert)了两个 Movie 实体实例:

try (StatelessSession statelessSession = sf.openStatelessSession()) { var firstMovie = new Movie(); firstMovie.setId(new ObjectId("573a1398f29313caabce9682")); firstMovie.setTitle("The General"); firstMovie.setYear(1926); var secondMovie = new Movie(); secondMovie.setId(new ObjectId("573a1398f29313caabce9683")); secondMovie.setTitle("Metropolis"); secondMovie.setYear(1927); statelessSession.upsertMultiple(List.of(firstMovie, secondMovie));}

以下实体映射在更新或插入(upsert)操作中不受支持。当更新或插入(upsert)使用这些映射之一的实体时,Hibernate ORM 扩展会抛出 FeatureNotSupportedException:

  • 具有使用 @Version 注释的字段的实体。

  • 具有使用 @Column(insertable = false) 注释的字段的实体。MongoDB 查询语言无法实现仅在操作匹配现有文档时写入字段。

  • 唯一持久属性是标识符的实体。对此类实体执行更新或插入(upsert)操作时,没有可更新的字段,因此 Hibernate ORM 扩展会拒绝该操作。

您可以执行以下操作从集合中删除文档:

  • 删除一个文档:在会话或实体管理器上调用 remove() 方法,并将要删除的实体实例作为参数传递。

  • 删除多个文档:将删除声明传递给会话或实体经理上的 createQuery() 或 createMutationQuery() 方法。然后,调用 executeUpdate() 方法将更改应用到数据库。

提示

要学习;了解有关使用 Hibernate ORM 删除数据的更多信息,请参阅以下资源:

The following example retrieves a document by its ObjectId value. Then, the example calls the remove() method on a session to delete the corresponding document from the sample_mflix.movies collection:

// Your ObjectId value might differMovie movieToDelete = session.get(Movie.class, new ObjectId("573a1399f29313caabcedc5d"));session.remove(movieToDelete);

The following example deletes all documents that have a year value of 1920 from the sample_mflix.movies collection. The example passes a delete statement to the createMutationQuery() method, and then calls the executeUpdate() method to apply the changes to the database:

var deleteResult = session.createMutationQuery( "delete Movie where year = :y") .setParameter("y", 1920) .executeUpdate();System.out.println("Number of movies deleted: " + deleteResult);

要学习有关使用 Hibernate ORM 执行 CRUD 操作的更多信息,请参阅以下资源:

To view more create, read, update, and delete examples, see the following sections of the Get Started tutorial:

要学习;了解有关使用 Hibernate ORM 扩展来运行查询的更多信息,请参阅以下指南: