介绍
对我来说,最令人困惑和不清楚的事情之一是,作为Java开发人员,一直是围绕事务管理的谜团,尤其是JPA如何处理事务管理。 事务什么时候开始,什么时候结束,实体的持久化方式,持久性上下文等等。 诸如Spring之类的框架也无助于理解概念,因为它们提供了另一层抽象,这使事情难以理解。 在今天的帖子中,我将尝试揭露JPA关于实体管理的规范,其事务规范以及如何更好地理解该概念如何帮助我们有效地设计和编码的某些秘密。 我们将努力保持讨论
尽管我们将同时研究Java SE(其中Java EE容器不可用)和基于Java EE的示例。
基本概念
在深入探讨更多细节之前,让我们快速遍历一些基础课程及其在JPA中的含义。
- EntityManager –管理实体的持久状态(或生命周期)的类。
- 持久性单元 –是实体类的命名配置。
- 持久性上下文 –是一组托管的实体实例。 实体类是持久性单元配置的一部分。
- 托管实体 –如果实体实例是持久性上下文的一部分,并且该实体管理器可以对其执行操作,则该实体实例将受到管理。
从上面的第一点和第三点,我们可以推断出实体管理器总是管理持久性上下文。 因此,如果我们了解持久性上下文,那么我们将了解EntityManager。
细节
JPA中的EntityManager
JPA中定义了EntityManager的三种主要类型。
- 容器管理和交易范围的实体管理器
- 容器管理和扩展范围实体管理器
- 应用程序管理的实体管理器
现在,我们将更详细地介绍其中的每一个。
容器管理的实体管理器
当应用程序的一个容器(例如Java EE容器或任何其他自定义容器,例如Spring)管理实体管理器的生命周期时,该实体管理器被称为“容器管理”。 获取容器管理的EntityManager的最常见方法是在EntityManager属性上使用@PersistenceContext批注。 这是定义EntityManager的示例。
public class EmployeeServiceImpl implements EmployeeService {
@PersistenceContext(unitName="EmployeeService")
EntityManager em;
public void assignEmployeeToProject(int empId, int projectId) {
Project project = em.find(Project.class, projectId);
Employee employee = em.find(Employee.class, empId);
project.getEmployees().add(employee);
employee.getProjects().add(project);
}
在上面的示例中,我们在EntityManager类型实例变量上使用了@PersistenceContext批注。 PersistenceContext批注具有属性“ unitName”,用于标识该上下文的持久性单元。
容器管理的实体管理器有两种形式:
- 交易范围的实体管理器
- 扩展范围实体管理器
请注意,上述范围实际上是指实体管理器管理的持久性上下文的范围。 它不是EntityManager本身的范围。
让我们依次查看它们中的每一个。
交易范围实体管理器
这是应用程序中最常用的实体管理器。 同样在上面的示例中,我们实际上是在创建事务作用域实体管理器。 每当解析由@PersistenceContext创建的引用时,都会返回事务作用域实体管理器。
使用事务作用域实体管理器的最大好处是它是无状态的。 这也使事务范围的EntityManager线程安全,因此实际上无需维护。 但是我们只是说EntityManager管理实体的持久性状态,而实体的持久性状态是注入EntityManager的持久性上下文的一部分。 那么,上述关于无国籍的说法如何呢?
答