• Hibernate EntityManager 指南


    1. 简介

    EntityManager是 Java Persistence API 的一部分。它主要实现 JPA 2.0 规范定义的编程接口和生命周期规则。

    此外,我们可以通过使用EntityManager 中的 API 来访问持久性上下文。

    在本教程中,我们将了解实体管理器的配置、类型和各种 API。

    2. Maven 依赖项

    首先,我们需要包含 Hibernate 的依赖项:

    1. org.hibernate
    2. hibernate-core
    3. 5.4.0.Final

    根据我们使用的数据库,我们还必须包含驱动程序依赖项:

    1. mysql
    2. mysql-connector-java
    3. 8.0.13

    hibernate-coremysql-connector-java依赖项在Maven Central上可用。

    3. 配置

    现在,让我们通过使用与数据库中的 MOVIE 表对应的电影实体来演示实体管理器

    在本文中,我们将使用EntityManagerAPI 来处理数据库中的Movie对象。

    3.1. 定义实体

    让我们首先使用@Entity注释创建与 MOVIE 表对应的实体:

    1. @Entity
    2. @Table(name = "MOVIE")
    3. public class Movie {
    4. @Id
    5. private Long id;
    6. private String movieName;
    7. private Integer releaseYear;
    8. private String language;
    9. // standard constructor, getters, setters
    10. }

    3.2.持久化.xml文件

    创建EntityManagerFactory时,持久性实现会在类路径中搜索META-INF/persistence.xml文件

    This file contains the configuration for the EntityManager:

    1. Hibernate EntityManager Demo
    2. com.baeldung.hibernate.pojo.Movie
    3. true

    如我们所见,我们定义了持久性单元,该单元指定由EntityManager 管理的基础数据存储。

    此外,我们还定义了基础数据存储的方言和其他 JDBC 属性。Hibernate与数据库无关。基于这些属性,Hibernate与基础数据库连接。

    4. 容器和应用程序托管实体管理器

    基本上,有两种类型的实体管理器:容器托管和应用程序管理。

    让我们仔细看看每种类型。

    4.1. 容器管理的实体管理器

    在这里,容器在我们的企业组件中注入了实体管理器

    换句话说,容器从EntityManagerFactory为我们创建了EntityManager

    1. @PersistenceContext
    2. EntityManager entityManager;

    这也意味着容器负责开始事务,以及提交或回滚事务。

    同样,容器负责关闭实体管理器,因此无需手动清理即可安全使用。即使我们尝试关闭容器管理的EntityManager,它也应该抛出IllegalStateException。

    4.2. 应用程序管理的实体管理器

    相反,实体管理器的生命周期由应用程序管理。

    事实上,我们将手动创建实体管理器,并管理它的生命周期。

    首先,让我们创建EntityManagerFactory:

    EntityManagerFactory emf = Persistence.createEntityManagerFactory("com.baeldung.movie_catalog");

    为了创建一个 EntityManager,我们必须在EntityManagerFactory 中显式调用createEntityManager():

    1. public static EntityManager getEntityManager() {
    2. return emf.createEntityManager();
    3. }

    由于我们负责创建EntityManager实例,因此我们也有责任关闭它们因此,我们应该在使用完每个实体管理器关闭它们。

    4.3. 线程安全

    EntityManagerFactory实例以及因此 Hibernate 的SessionFactory实例是线程安全的。因此,在并发上下文中编写以下内容是完全安全的:

    1. EntityManagerFactory emf = // fetched from somewhere
    2. EntityManager em = emf.createEntityManager();

    另一方面,EntityManager实例不是线程安全的,旨在用于线程受限的环境。这意味着每个线程都应该获取它的实例,使用它,并在最后关闭它。

    使用应用程序管理的实体管理器时,可以轻松创建线程受限的实例:

    1. EntityManagerFactory emf = // fetched from somewhere
    2. EntityManager em = emf.createEntityManager();
    3. // use it in the current thread

    但是,当使用容器管理的实体管理器时,事情变得违反直觉:

    1. @Service
    2. public class MovieService {
    3. @PersistenceContext // or even @Autowired
    4. private EntityManager entityManager;
    5. // omitted
    6. }

    似乎应该为所有操作共享一个实体管理器实例。但是,容器(JakartaEE 或 Spring)在这里注入了一个特殊的代理,而不是一个简单的EntityManager。例如,Spring 注入了一个类型为 SharedEntityManagerCreator 的代理。

    每次我们使用注入的实体管理器,这个代理要么重用现有的实体管理器,要么创建一个新的实体管理器。重用通常发生在我们在视图中启用类似 Open Session/EntityManager 之类的东西时。

    无论哪种方式,容器都确保每个实体管理器都限制在一个线程中

    5. 休眠实体操作

    EntityManagerAPI 提供了一组方法。我们可以通过使用这些方法与数据库进行交互。

    5.1. 持久化实体

    为了使对象与 EntityManager 相关联,我们可以使用persist() 方法:

    1. public void saveMovie() {
    2. EntityManager em = getEntityManager();
    3. em.getTransaction().begin();
    4. Movie movie = new Movie();
    5. movie.setId(1L);
    6. movie.setMovieName("The Godfather");
    7. movie.setReleaseYear(1972);
    8. movie.setLanguage("English");
    9. em.persist(movie);
    10. em.getTransaction().commit();
    11. }

    将对象保存到数据库中后,它将处于持久状态。

    5.2. 加载实体

    为了从数据库中检索对象,我们可以使用find() 方法。

    在这里,该方法按主键搜索。实际上,该方法需要实体类类型和主键:

    1. public Movie getMovie(Long movieId) {
    2. EntityManager em = getEntityManager();
    3. Movie movie = em.find(Movie.class, new Long(movieId));
    4. em.detach(movie);
    5. return movie;
    6. }

    但是,如果我们只需要对实体的引用,我们可以改用getReference() 方法。实际上,它将代理返回给实体:

    Movie movieRef = em.getReference(Movie.class, new Long(movieId));

    5.3. 分离实体

    如果我们需要从持久性上下文中分离一个实体,我们可以使用detach() 方法。我们将要分离的对象作为参数传递给方法:

    em.detach(movie);

    实体从持久性上下文中分离后,它将处于分离状态。

    5.4. 合并实体

    实际上,许多应用程序需要跨多个事务进行实体修改。例如,我们可能希望检索一个事务中的实体以呈现到 UI。然后,另一个事务将引入UI中所做的更改。

    对于这种情况,我们可以使用merge() 方法。合并方法有助于将对分离实体所做的任何修改引入托管实体:

    1. public void mergeMovie() {
    2. EntityManager em = getEntityManager();
    3. Movie movie = getMovie(1L);
    4. em.detach(movie);
    5. movie.setLanguage("Italian");
    6. em.getTransaction().begin();
    7. em.merge(movie);
    8. em.getTransaction().commit();
    9. }

    5.5. 查询实体

    此外,我们可以利用 JPQL 来查询实体。我们将调用getResultList() 来执行它们。

    当然,如果查询只返回一个对象,我们可以使用getSingleResult():

    1. public List queryForMovies() {
    2. EntityManager em = getEntityManager();
    3. List movies = em.createQuery("SELECT movie from Movie movie where movie.language = ?1")
    4. .setParameter(1, "English")
    5. .getResultList();
    6. return movies;
    7. }

    5.6. 删除实体

    此外,我们可以使用remove() 方法从数据库中删除实体。请务必注意,对象不是分离的,而是删除的。

    在这里,实体的状态从持久更改为新:

    1. public void removeMovie() {
    2. EntityManager em = HibernateOperations.getEntityManager();
    3. em.getTransaction().begin();
    4. Movie movie = em.find(Movie.class, new Long(1L));
    5. em.remove(movie);
    6. em.getTransaction().commit();
    7. }

    6. 结论

    在本文中,我们探讨了 Hibernate 中的EntityManager。我们查看了类型和配置,并了解了 API 中可用于处理持久性上下文的各种方法。

    与往常一样,本文中使用的代码可在Github 上找到。

  • 相关阅读:
    为什么要学习GoF设计模式?
    智能电表上的模块发热正常吗?
    数据标准详细概述-2022
    在jar里限制指定的包名才可调用(白名单)。
    SpringBoot_快速入门
    一次node文件操作过多排查过程总结
    机房设备如何把关?学会这个技巧
    c++11产生指定范围内均匀分布随机数、产生大量不重复随机数
    WPF/C#实现图像滤镜优化方案:打造炫目视觉体验!
    Xshell使用技巧及常用配置
  • 原文地址:https://blog.csdn.net/allway2/article/details/128176882