Overview
In this guide, you can learn how to use the MongoDB Extension for Hibernate ORM to perform transactions. Transactions allow you to run a series of operations that change data only if the entire transaction is committed.
在MongoDB中,事务在逻辑会话中运行。会话是要按顺序运行的一组相关读取或写入操作。会话启用为一群组操作启用因果一致性,并允许您在符合ACID的ACID 事务中运行操作,该ACID 事务满足原子性、一致性、隔离性和持久性的预期。
Hibernate ORM 扩展支持以下用于管理会话和事务的 API:
Hibernate
Session: Allows you to use theorg.hibernate.TransactionAPI to group your database operations. To learn more, see Hibernate Transaction API in the Hibernate ORM user guide.Jakarta Persistence
EntityManager:指示 Hibernate ORMSession在内部管理 ,并允许您使用jakarta.persistence.EntityTransactionAPI对数据库操作群组。要学习;了解更多信息,请参阅 Jakarta EE 文档中的 jakarta.persistence包。
样本数据
本指南中的示例使用Movie 实体,它表示Atlas示例数据集中的sample_mflix.movies 集合。Movie 实体具有以下定义:
import com.mongodb.hibernate.annotations.ObjectIdGenerator; import org.bson.types.ObjectId; import jakarta.persistence.Entity; import jakarta.persistence.Id; import jakarta.persistence.Table; public class Movie { private ObjectId id; private String title; private String plot; private int year; private String[] cast; public Movie(String title, String plot, int year, String[] cast) { this.title = title; this.plot = plot; this.year = year; this.cast = cast; } 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 String[] getCast() { return cast; } public void setCast(String[] cast) { this.cast = cast; } }
要学习;了解如何创建Java应用程序以使用MongoDB Extension for Hibernate ORM 与此MongoDB示例集合交互,请参阅 入门教程。
创建会话
要与MongoDB数据交互,您必须在会话中运行所有数据库操作。本节介绍如何通过以下方式管理数据库会话:
使用 Hibernate 会话:使用 Hibernate 的原生API从 创建
SessionSessionFactory使用 JPA EntityManager:使用 Jakarta Persistence API从 创建
EntityManagerEntityManagerFactory
使用 Hibernate 会话
要启动 Hibernate Session,请执行以下步骤:
使用
getSessionFactory()方法从HibernateUtil实用程序类中检索SessionFactory。SessionFactory存储您的MongoDB连接配置,并且可以打开新的数据库会话。通过在
SessionFactory实例上调用openSession()方法来创建Session。运行数据库操作后,对这两个实例使用
close()方法关闭SessionFactory和Session。
以下示例在会话中运行数据库查询,并从 sample_mflix.movies集合中检索 title 值为 "Erin Brockovich" 的文档:
var sf = HibernateUtil.getSessionFactory(); Session session = sf.openSession(); var movie = session.createQuery("from Movie where title = :t", Movie.class) .setParameter("t", "Erin Brockovich") .getSingleResult(); System.out.println("Title: " + movie.getTitle() + ", Year: " + movie.getYear()); session.close(); sf.close();
Title: Erin Brockovich, Year: 2000
还可以使用 Java 的 try-with-resources声明来简化会话管理逻辑并自动关闭会话,如以下代码所示:
var sf = HibernateUtil.getSessionFactory(); try (Session session = sf.openSession()) { var movie = session.createQuery("from Movie where title = :t", Movie.class) .setParameter("t", "Erin Brockovich") .getSingleResult(); System.out.println("Title: " + movie.getTitle() + ", Year: " + movie.getYear()); } sf.close();
使用 JPA EntityManager
提示
在使用EntityManager 之前,您必须创建一个声明持久性单元的persistence.xml 文件。要学习;了解更多信息,请参阅 Hibernate ORM 文档中的使用 JPA 标准 API 的教程。
要启动 Jakarta Persistence API (JPA) EntityManager,请执行以下步骤:
通过调用
createEntityManagerFactory()方法从persistence.xml文件创建EntityManagerFactory,该方法会在内部创建SessionFactory。通过对
EntityManagerFactory实例调用createEntityManager()方法来创建EntityManager,这会在内部创建Session。运行数据库操作后,在
EntityManagerFactory和EntityManager实例上调用close()方法以关闭这两个实例。
以下示例在实体管理器中运行数据库查询,并从 sample_mflix.movies集合中检索 year 值为 1929 的文档:
// Replace <persistence unit> with the name of your persistence unit in the persistence.xml file EntityManagerFactory emf = Persistence.createEntityManagerFactory("<persistence unit>"); EntityManager entityManager = emf.createEntityManager(); var results = entityManager.createQuery("select m from Movie m where m.year = :y", Movie.class) .setParameter("y", 1929) .getResultList(); results.forEach(movie -> System.out.println(movie.getTitle())); entityManager.close(); emf.close();
The Broadway Melody Queen Kelly Asphalt Hallelujah Disraeli Applause Lambchops
在 Jakarta Persistence v3.1 或更高版本中,您可以使用 Java 的 try-with-resources声明自动关闭 EntityManager,如“Hibernate 会话”部分所示。
运行事务
要修改MongoDB数据,必须在ACID 事务中运行所有写入。本节介绍如何通过以下方式管理ACID 事务:
使用 Hibernate 事务:使用 Hibernate 的原生
org.hibernate.TransactionAPI从 启动ACID 事务Session使用 JPA EntityTransaction :使用
jakarta.persistence.EntityTransactionAPI从EntityManager
使用 Hibernate 事务
要启动 Hibernate Transaction,请在 Session实例上调用 beginTransaction() 方法。运行操作并使用 persist() 方法在会话中注册更改后,通过调用 commit() 方法提交ACID 事务。
以下示例使用ACID 事务创建新的 Movie 实体,并将其作为文档插入到 sample_mflix.movies集合中。突出显示的行开始并提交ACID 事务。
var sf = HibernateUtil.getSessionFactory(); Session session = sf.openSession(); Transaction tx = session.beginTransaction(); var newMovie = new Movie(); newMovie.setTitle("Lady Bird"); session.persist(newMovie); tx.commit(); session.close(); sf.close();
使用 JPA EntityTransaction
要创建 JPA EntityTransaction,请对 EntityManager 调用 getTransaction() 方法。此方法检索一个 EntityTransaction,其中包装了根本的Hibernate Transaction。然后,调用 begin() 方法启动ACID 事务。运行操作并使用 persist() 方法向实体管理器注册更改后,通过调用 commit() 方法提交ACID 事务。
以下示例使用 EntityTransaction 从 sample_mflix.movies集合中删除文档。突出显示的行开始并提交ACID 事务。
// Replace <persistence unit> with the name of your persistence unit in the persistence.xml file EntityManagerFactory emf = Persistence.createEntityManagerFactory("<persistence unit>"); EntityManager entityManager = emf.createEntityManager(); entityManager.getTransaction().begin(); // Your ObjectId value might differ Movie movieToDelete = entityManager.find(Movie.class, new ObjectId("573a1399f29313caabcedc5d")); entityManager.remove(movieToDelete); entityManager.getTransaction().commit(); entityManager.close(); emf.close();
事务错误处理
要放弃ACID 事务中的所有数据更改,请对 Hibernate Transaction 或 JPA EntityTransaction 调用 rollback() 方法。调用此方法后,Hibernate ORM 将恢复未提交的更改并清除持久化上下文。
以下示例将在代码抛出错误时回滚ACID 事务。选择 Hibernate Transaction 或 JPA EntityTransaction标签页以查看相应的代码:
Session session = sessionFactory.openSession(); Transaction tx = null; try { tx = session.beginTransaction(); Movie movie = new Movie(); movie.setTitle("Control Alt Delete"); session.persist(movie); tx.commit(); } catch (Exception e) { if (tx != null) { tx.rollback(); } e.printStackTrace(); } finally { session.close(); }
EntityManager entityManager = emf.createEntityManager(); EntityTransaction tx = entityManager.getTransaction(); try { tx.begin(); Movie movie = new Movie(); movie.setTitle("Control Alt Delete"); entityManager.persist(movie); tx.commit(); } catch (Exception e) { if (tx != null && tx.isActive()) { tx.rollback(); } e.printStackTrace(); } finally { entityManager.close(); }