jpa 事务嵌套事务_JPA 2 | EntityManagers,事务及其周围的一切

jpa 事务嵌套事务

介绍

对我来说,最令人困惑和不清楚的事情之一是,作为Java开发人员,一直是围绕事务管理的谜团,尤其是JPA如何处理事务管理。 事务什么时候开始,什么时候结束,实体的持久化方式,持久性上下文等等。 诸如Spring之类的框架也无助于理解概念,因为它们提供了另一层抽象,这使事情难以理解。 在今天的帖子中,我将尝试揭露JPA关于实体管理的规范,其事务规范以及如何更好地理解该概念如何帮助我们有效地设计和编码的某些秘密。 我们将努力保持讨论

尽管我们将同时研究Java SE(其中没有Java EE容器)和基于Java EE的示例。

基本概念

在深入探讨更多细节之前,让我们快速完成一些基础课程及其在JPA中的含义。

  1. EntityManager –一个管理实体的持久状态(或生命周期)的类。
  2. 持久性单元 –是实体类的命名配置。
  3. 持久性上下文 –是一组托管的实体实例。 实体类是持久性单元配置的一部分。
  4. 托管实体 –如果实体实例是持久性上下文的一部分,并且该实体管理器可以对其执行操作,则该实体实例将受到管理。

从上面的第一点和第三点,我们可以推断出实体管理器总是管理持久性上下文。 因此,如果我们了解持久性上下文,我们将了解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”,用于标识该上下文的持久性单元。

容器管理的实体管理器有两种形式:

  1. 交易范围的实体管理器
  2. 扩展范围实体管理器

请注意,上述范围实际上是指实体管理器管理的持久性上下文的范围。 它不是EntityManager本身的范围。

让我们依次查看它们中的每一个。

交易范围实体管理器

这是应用程序中最常用的实体管理器。 同样在上面的示例中,我们实际上是在创建事务作用域实体管理器。 每当解析由@PersistenceContext创建的引用时,都会返回事务作用域实体管理器。

使用事务作用域实体管理器的最大好处是它是无状态的。 这也使事务范围的EntityManager线程安全,因此实际上无需维护。 但是我们只是说EntityManager管理实体的持久状态,而实体的持久状态是注入EntityManager的持久性上下文的一部分。 那么,上述关于无国籍状态的说法又如何呢?

答案在于所有容器管理的实体管理器都依赖于JTA事务。 每次在实体管理器上调用操作时,容器代理(容器在实例化时在实体管理器周围创建一个代理)都会检查JTA事务上是否存在任何持久性上下文。 如果找到一个,则实体管理器将使用此持久性上下文。 如果找不到,则将创建一个新的持久性上下文并将其与事务关联。

让我们以上面讨论的相同示例来了解实体管理器和事务创建的概念。

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); }

在上面的示例中,assignEmployeeToProject方法的第一行正在EntityManager上调用find方法。 查找调用将强制容器检查现有交易。 是否存在事务(例如,对于Java EE中的无状态会话Bean,容器在每次调用Bean上的方法时都保证事务可用)或不存在。 如果事务不存在,它将抛出异常。 如果存在,它将检查持久性上下文是否存在。 自从第一次调用EntityManager的任何方法以来,持久性上下文尚不可用。 然后,实体管理器将创建一个并使用它来查找项目bean实例。

在下一个查找调用中,实体管理器已经具有关联的事务以及与其关联的持久性上下文。 它使用相同的事务来查找员工实例。 在方法的第二行结束时,将同时管理项目和员工实例。 在方法调用结束时,将提交事务,并保留人员和员工的托管实例。 要记住的另一件事是,当事务结束时,持久性上下文消失了。

扩展范围实体管理器

如果并且当您希望持久性上下文在方法范围之外可用时,请使用具有扩展范围的实体管理器。 理解扩展范围实体管理器的最好方法是以一个类为例,该类需要维护某种状态(该状态是由于诸如myEntityManager.find(“ employeeId”)之类的事务请求而创建的,然后使用该雇员),并且通过各种业务方法共享状态。

因为Persistence Context在方法调用之间共享并且用于维护状态,所以除非您在有状态会话Bean中使用它们(容器负责使其成为线程安全的),否则它通常不是线程安全的。 重申一下,如果您使用的是Java EE容器,则将在Stateful Session Bean(带有@Stateful注释的类)内使用扩展范围实体管理器。 如果您决定在有状态bean之外使用它,则该容器不能保证您可以安全地执行线程操作,而必须自己处理。 如果您使用的是像Spring这样的第三方容器,情况也是如此。

让我们看一下使用状态会话Bean时Java EE环境中扩展作用域实体管理器的示例。

该示例中的目标是创建一个业务类,该业务类具有在LibraryUser Entity实例上工作的业务方法。 让我们将此具有业务接口UserManagementService的业务类LibraryUserManagementService命名。 LibraryUserManagementService在LibraryUsers实体实例上工作。 图书馆可以将多本书借给LibraryUser。

这是描述上述情况的有状态会话Bean的示例。

@Stateful 
public class LibraryUserManagementService implements UserManagementService { @PersistenceContext(unitName="UserService") EntityManager em; LibraryUser user; public void init(String userId) { user = em.find(LibraryUser.class, userId); } public void setUserName(String name) { user.setName(name); } public void borrowBookFromLibrary(BookId bookId) { Book book = em.find(Book.class, bookId); user.getBooks().add(book); book.setLendingUser(user); } // ... @Remove public void finished() { } 
}

在上面使用用户实例的情况下,更自然的是先获得一个实例,然后逐步进行操作,只有完成后,我们才应保留用户实例。 但是,问题在于实体管理器是事务范围的。 这意味着init将在其自身的事务中运行(因此具有其自身的持久性上下文),而roweBookFromLibrary将在其自身的事务中运行。 结果,init方法一结束,用户对象就变得不受管理。

为了确切地解决此类问题,我们使用PersistenceContextType.EXTENDED类型的实体管理器。

这是带有PersistenceContextType EXTENDED的修改后的示例,可以很好地工作。

@Stateful 
public class LibraryUserManagementService implements UserManagementService { @PersistenceContext(unitName="UserService" , type=PersistenceContextType.EXTENDED) EntityManager em;LibraryUser user; public void init(String userId) { user = em.find(LibraryUser.class, userId); } public void setUserName(String name) { user.setName(name); } public void borrowBookFromLibrary(BookId bookId) { Book book = em.find(Book.class, bookId); user.getBooks().add(book); book.setLendingUser(user); } // ... @Remove public void finished() { } 
}

在上述场景中,用于管理用户实例的PersistenceContext是由Java EE容器在Bean初始化时创建的,并且在调用完成的方法(在该时间提交事务)之前可用。

应用范围的实体管理器

不是由容器而是由应用程序本身创建的实体管理器是应用程序范围的实体管理器。 为了使定义更清晰,每当我们通过在EntityManagerFactory实例上调用createEntityManager来创建实体管理器时,实际上是在创建应用程序范围的实体管理器。 所有基于Java SE的应用程序实际上都使用应用程序范围的实体管理器。 JPA为我们提供了一个Persistence类,该类用于最终创建应用程序范围的实体管理器。

以下是如何创建应用程序范围的EM的示例:

EntityManagerFactory emf = Persistence.createEntityManagerFactory("myPersistenceUnit"); EntityManager em = emf.createEntityManager();

请注意,要创建应用程序范围的EntityManager,在应用程序的META-INF文件夹中需要有一个persistence.xml文件。

EntityManager可以通过两种方式创建。 上面已经显示了一个。 创建EntityManager的另一种方法是将一组属性作为参数传递给
createEntityManagerFactory方法。

EntityManagerFactory emf = Persistence.createEntityManagerFactory("myPersistenceUnit" , myProperties); EntityManager em = emf.createEntityManager();

如果要创建自己的应用程序托管实体管理器,请确保在每次使用完它后都将其关闭。 这是必需的,因为您现在正在管理应如何以及何时创建和使用EntityManager。

交易管理

交易与实体直接相关。 实质上,管理事务意味着要管理实体生命周期(创建,更新,删除)的管理方式。 理解事务管理的另一个关键是要了解持久性上下文如何与事务交互。 值得注意的是,从最终用户的角度来看,即使我们使用EntityManager的实例,EntityManager的唯一作用是确定持久性上下文的生存期。 它在决定持久化上下文应如何表现方面没有任何作用。 重申一下,持久性上下文是一组实体实例的托管集合。 每当事务开始时,Persistence Context实例都会与之关联。 当事务结束时(例如,提交),持久性上下文将被刷新并与事务解除关联。

JPA支持两种类型的事务管理类型。

  • 资源本地交易
  • JTA或全球交易

资源本地事务是指JDBC驱动程序的本机事务,而JTA事务是指JEE服务器的事务。 资源本地事务涉及单个事务资源,例如JDBC连接。 每当在单个事务中需要两个或更多资源(例如JMS连接和JDBC连接)时,都可以使用JTA事务。
容器管理的实体管理器始终使用JTA事务,因为容器负责事务生命周期管理并在多个事务资源中产生事务。 应用程序管理的实体管理器可以使用资源本地事务或JTA事务。

通常,在JTA或全局事务中,第三方事务监控器会在事务中获取不同的事务资源,为提交做准备,最后提交事务。 首先准备事务资源(通过空运行)然后提交(或回滚)的过程称为两阶段提交。

有关XA协议的附带说明 –在全球交易中,交易监视器必须不断与不同的交易资源进行对话。 不同的交易资源会说不同的语言,因此交易监视器可能无法理解。 XA是一个协议规范,为事务监视器与不同的事务资源进行交互提供了通用基础。 JTA是说XA的全球事务监控器规范,因此能够管理多个事务资源。 兼容Java EE的服务器具有内置的JTA实现。其他容器(例如Spring)可以自己编写或使用其他实现(例如Java Open Transaction Manager,JBoss TS等)来支持JTA或全局事务。

持久性上下文,事务和实体管理器

持久性上下文可以与单个或多个事务关联,也可以与多个实体管理器关联。 持久性上下文已向事务注册,以便在提交事务时可以刷新持久性上下文。 事务开始时,实体管理器将查找活动的持久性上下文实例。 如果不可用,它将创建一个并将其绑定到事务。 通常,持久性上下文的范围与事务紧密相关。 当事务结束时,与该事务关联的持久性上下文实例也结束。 但是有时,在大多数情况下,在Java EE世界中,我们需要事务传播,这是在单个事务中的不同实体管理器之间共享单个持久性上下文的过程。

持久性上下文可以有两个范围:

  • 事务范围的持久性上下文
  • 扩展范围的持久性上下文

我们已经讨论了事务/扩展范围的实体管理器,并且我们也知道实体管理器可以是事务或扩展范围的。 关系不是偶然的。 事务范围的实体管理器创建事务范围的持久性上下文。 扩展范围实体管理器使用扩展持久性上下文。 扩展持久性上下文的生命周期与Java EE环境中的有状态会话Bean相关联。

让我们简要地讨论这些持久性上下文

事务范围的持久性上下文

TSPC仅在需要时由实体管理器创建。 仅当首次调用实体管理器上的方法时,事务作用域实体管理器才创建TSPC。 因此,持久性上下文的创建是懒惰的。 如果已经存在传播的持久性上下文,则实体管理器将使用该持久性上下文。

了解持久性上下文传播对于识别和调试代码中与事务相关的问题非常重要。 让我们看一个如何传播事务范围的持久性上下文的示例。

ItemDAOImpl.java:

public class ItemDAOImpl implements ItemDAO { @PersistenceContext(unitName="ItemService") EntityManager em; LoggingService ls; @TransactionAttribute()public void createItem(Item item) { em.persist(item); ls.log(item.getId(), "created item"); } // ... 
}

LoggingService.java:

public class LoggingService implements AuditService { @PersistenceContext(unitName="ItemService") EntityManager em; @TransactionAttribute()public void log(int itemId, String action) { // verify item id is valid if (em.find(Item.class, itemId) == null) { throw new IllegalArgumentException("Unknown item id"); } LogRecord lr = new LogRecord(itemId, action); em.persist(lr); } }

调用ItemDAOImpl的createItem方法时,将在实体管理器实例上调用persist方法。 假设这是对实体管理器方法的第一次调用。 实体管理器将查找单元名称为“ ItemService”的任何传播的持久性上下文。 它找不到一个,因为这是对实体管理器的第一个调用。 因此,它创建了一个新的持久性上下文实例并将其附加到自身。 然后,它继续保存Item对象。 持久化项目对象后,我们将调用以记录刚刚持久化的项目信息。 请注意,LoggingService有其自己的EnitityManager实例,方法日志中具有注释@TransactionAttribute(如果在Java EE envt中并且将bean声明为EJB,则不需要此注释)。
由于TransactionAttribute的默认TransactionAttributeType为REQUIRED,因此LoggingService中的实体管理器将查找以前的事务中可能可用的任何持久性上下文。 它找到一个在ItemDAOImpl的createItem方法内部创建的对象,并使用相同的对象。 这就是为什么即使实际项目尚未持久到数据库(因为尚未提交事务),LoggingService中的实体管理器仍能够找到它,因为持久性上下文已从ItemDAOImpl传播到LoggingService 。

扩展持久性上下文

事务范围持久性上下文是为每个事务创建的(在不传播的情况下),而扩展持久性上下文仅创建一次,并由管理扩展持久性上下文生命周期的类范围内的所有事务使用。 对于Java EE,由状态会话Bean管理扩展的持久性上下文的生命周期。 有状态会话bean的创建是EAGER。 如果是容器托管事务,则在类上的方法被调用后立即创建它。 对于应用程序管理的事务,将在调用userTransaction.begin()时创建。

摘要

在这篇博客文章中,已经讨论了很多东西,实体管理器,事务管理,持久性上下文,所有这些东西如何相互作用以及如何相互配合。

我们讨论了容器管理的实体管理器和应用程序管理的实体管理器,事务范围和扩展范围持久性上下文,事务传播之间的区别。 该博客的大部分材料是阅读了精彩的书: Pro JPA 2的结果 。 如果您想更深入地了解JPA的工作原理,我建议您阅读它。

参考: JPA 2 | JavaWorld博客博客中的JCG合作伙伴 Anuj Kumar提供了EntityManagers,Transactions及其周围的一切 。

翻译自: https://www.javacodegeeks.com/2013/06/jpa-2-entitymanagers-transactions-and-everything-around-it.html

jpa 事务嵌套事务

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/348233.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Matlab中装载和存储实验数据的操作

一、装载实验数据 例如,以下程序,其中path是路径,strcat函数将后面的参数组合成一个字符串。load函数将由twoband_CAP4_400MBd_2000MSa_float_字符串与Tx.txt构成的: twoband_CAP4_400MBd_2000MSa_float_Tx.txt文件读取至matlab中。 numSam…

无服务器革命:好,坏和丑

“这是愚蠢的。 比愚蠢还糟:这是一场营销炒作。” ‐ 理查德斯托曼 ( Richard Stallman)对云计算的评论,2008年9月 而且,十年后,当有人提到这个词时,您开始三思而后行:是到天上掉的…

MATLAB中,信号的频谱图该怎么绘制?横坐标如何标注出频率值?

一、什么是频谱? 频谱的全称是频率谱密度。在对时域信号进行认识和研究的过程中非常不便,那我们该如何更直观地认识信号,更清楚地了解信号的特点呢? 利用傅里叶变换将时域信号变换到频域。 我们知道,在通信领域里傅…

Verilog HDL中模块参数传递的方法

文章目录前言一、参数传递二、参数传递方法1.方法一2.方法二3.方法三总结前言 “parameter”是Verilog HDL中的一个关键字,代表着参数型常量,即用parameter来定义一个标识符代表一个常量,这样可以提高程序的可读性与可维护性。 例如&#xf…

仔细看看_仔细看看,您会发现需要改进的地方

仔细看看我建议您做一个练习:明天早上返回工作时,浏览项目的源代码,并尝试寻找重构的机会。 即使老板没有要求也要这样做。 这样做是因为您想要一些激动人心的工作时间。 重构是改变已经可以正常工作的艺术 。 但是要进行重构,您…

Verilog HDL中位运算符、逻辑运算符和缩减运算符的区别

文章目录前言一、单目运算符、双目运算符和三目运算符二、位运算符三、逻辑运算符四、缩减运算符五、总结前言 我们在学习和理解Verilog HDL中的一些运算符的意义时,可能会对一些运算符的使用产生混乱,因此本文整理了Verilog HDL中&与&&、|…

Verilog HDL中容易生成锁存器的两种情况

在Verilog HDL的程序设计中,有两种情况会生成锁存器。 第一种情况 在always块中使用if语句,但是没有else,这会导致当条件不成立时,没有其他语句可执行,使得被赋值的寄存器一直保持不变,”锁存“住。 第二…

Spring Security与Maven教程

1.简介 在这篇文章中,我们将演示如何针对非常特定的用例将Maven依赖项用于Spring Security。 我们使用的所有库的最新版本都可以在Maven Central上找到。 在项目中,了解Maven依赖项的工作方式和管理方式对于有效的构建周期非常重要,并且对于…

EbN0、SNR、0.1nmOSNR的区别与联系

文章目录前言一、SNR与EbN0二、0.1nmOSNR1、波长宽度与带宽的换算2、0.1nmOSNR2.1、单极化信号2.2、双极化信号总结前言 无论是无线通信、光通信或者可见光通信系统中,我们经常会遇到信噪比的概念,但大多数,我们用的都是信号与噪声功率比&am…

利用Verilog HDL实现序列检测器,附上仿真程序。

文章目录一、序列检测器二、状态转移图三、序列检测器Verilog HDL程序1、源程序2、测试平台程序四、仿真结果五、总结一、序列检测器 序列检测器的逻辑功能就是将一个指定的比特序列从一串较长的比特流中识别出来。 例如:针对一个较长的比特流01001001001111010101…

在Java中使用Google的协议缓冲区

最近发布了 有效的Java第三版 ,我一直对确定此类Java开发书籍的更新感兴趣,该书籍的最新版本仅通过Java 6进行了介绍 。 在此版本中,显然有与Java 7 , Java 8和Java 9密切相关的全新项目,例如第7章(“ Lamb…

不同阶QAM调制星座图中,符号能量的归一化计算原理

文章目录前言一、归一化能量计算原理二、Matlab中如何得到归一化能量符号总结前言 在基于QAM调制的matlab仿真程序中,我们通常会产生二进制比特流,并最终映射成QAM符号,该符号大都是格雷编码的。在坐标系中,相邻符号之间的横纵坐…

4qam、16qam、64qam、256qam理论仿真曲线

本博文给出了4qam、16qam、64qam、256qam理论仿真曲线,画出了EbN0 vs BER的曲线图,可以作为大家学习的一个参考。 仿真结果: %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % Theoretical ber curves of different orde…

建立时间、保持时间与亚稳态

文章目录一、建立时间与保持时间二、亚稳态现象总结一、建立时间与保持时间 建立时间(set up time)是指在触发器的时钟信号上升沿到来以前,数据从不稳定到稳定所需要的时间,一般用TsuT_{su}Tsu​表示。 保持时间是指在触发器的时…

java ee空指针_Java EE 7是最终版本。 思想,见解和进一步的指针。

java ee空指针我们花了不到三年的时间才推出了下一个Java EE版本 。 今年4月16日, JCP EC对JSR 342进行了投票并获得批准。 这是一个成功的故事,因为在去年八月下旬的最后时刻撤消了拥有云就绪平台的最初想法。 作为EG的成员,撰写即将发布的功…

Java的原始字符串文字

似乎“ 原始字符串文字 ”即将出现在Java中。 JEP 326开始的(“原始字符串字面量”) 发行JDK-8196004 ,并宣布为“新JEP候选人” 3月2日的JEP和相关问题的人指出,“Java的仍然是一小群现代编程语言中的一个不为原始字符串提供语言…

Java可能使用UTF-8作为其默认字符集

由于基于Java的应用程序通常用于各种各样的操作系统和环境中,因此Java开发人员经常会遇到与基于字符的输入和输出有关的问题 。 涉及这些问题的博客文章包括《警察的恐怖:默认语言环境,默认字符集和默认时区》 ; 注释JDK默认数据 …

rest api_摆脱困境:向REST API添加验证

rest api我对此感到有些ham愧,但是直到昨天,我才知道我可以通过使用Valid和RequestBody批注将验证添加到REST API中。 这在Spring MVC 3.0中不起作用,由于某种原因,我没有注意到在Spring MVC 3.1中添加了对此功能的支持 。 我从不…

2020-08-07 光纤通信第二章知识点整理

目录 2.1 半导体激光器 2 2.1.1 激光原理的基础知识 2 2.1.2 激光激射条件 3 2.1.3 结构理论 4 2.1.4 典型分类 6 2.1.5 模式概念 7 2.1.6 基本性质 8 2.2 半导体发光二极管 10 2.2.1 工作原理 10 2.2.2 结构和分类 10 2.2.3 主要性质 10 2.3 光源的直接调制 11 2.3…

静态分析的教育方面

加入我们项目的新程序员经常会问我们是否具有自动格式化工具,以使Java代码看起来完全符合Qulice的期望。 (Quili是我们使用的静态分析器。)我总是回答说,拥有这样一个自动代码抛光器只会有害,不会帮助项目及其成员改进…