JPA规范定义了几种类型的EntityManagers / Persistence Context。 我们可以有:

  • 扩展的和事务范围的EntityManager,
  • 容器管理或应用程序管理的EntityManager。
  • JTA或本地资源EntityManager,

除了上述区别外,我们还可以在其中存在EntityManager / Persistence Context的两个主要上下文– Java EEJava SE 。 并非每个选项都适用于Java EE,并且并非每个选项都适用于Java SE。 在本文的其余部分, 我将介绍Java EE环境

好的,因此在继续本文之前的主题之前,这是使用EntityManagerFactory手动创建的Java EE中EntityManager的行为-我们仅简要介绍上述EM类型。

扩展与事务范围

此功能告诉我们EntityManager的操作是否可能跨越多个事务。 默认情况下,使用事务性持久性上下文,这意味着当提交当前事务时,将清除所有更改,并分离所有受管实体。 扩展范围仅适用于有状态EJB。 这非常合理,因为SFSB可以保存状态,因此不必终止一种业务方法就意味着结束事务。 使用SLSB时,情况就不同了–我们有业务方法必须在业务方法完成时结束,因为在下一次调用中,我们不知道我们将以哪个EJB实例结尾。 SLSB仅允许事务范围的EntityManager。 您可以控制在EntityManager注入期间EntityManager是扩展的还是事务的:

@PersistenceContext(type=javax.persistence.PersistenceContextType.EXTENDED)
EntityManager em;

默认情况下为javax.persistence.PersistenceContextType.TRANSACTION 。 附带说明–使用扩展的EntityManager可能允许您创建一些有趣的解决方案; 看看具有事务性保存方法技巧的 Adam Bien的无事务bean 。 他使用这种方法使事务开始和结束时自动清除所有更改(并且他实际上通过调用特殊的人工方法来做到这一点。)仅在容器管理的EntityManagers的情况下才允许扩展和事务范围的PersistenceContext。

容器管理与应用程序管理

在绝大多数Java EE应用程序中,您只是使用@PersistenceContext注入EntityManager,如下所示:

@PersistenceContext
EntityManager em;

实际上,这意味着您要让容器为您的EntityManager注入 (容器是在后台从EntityManagerFactory创建的。)这意味着EntityManager是由容器管理的。 另外,您可以从EntityManagerFactory自己创建一个EntityManager。 您可以通过注入获得它:

@PersistenceUnit
EntityManagerFactory emf;

然后,要获取EntityManager,您需要调用emf.createEntityManager() 。 就是这里–您正在使用由应用程序管理的EntityManager应用程序(您)负责创建和删除EntityManager。 每个应用程序管理的持久性上下文都有扩展的范围。

如果要控制已创建的EM,则可以使用-例如,要为基础JPA实现程序设置一些属性,或者只是在业务方法将其投入使用之前插入自己。 但是,您将需要跨事务涉及的多个bean移动创建的EntityManager –容器不会为您这样做,并且每次调用emf.createEntityManager()您都在创建一个与新PersistenceContext连接的EntityManager。 。 您可以使用CDI进行EntityManager的共享,但这是最后一节之一的主题。

JTA与本地资源

此属性定义您是要JTA管理EntityManager的事务,还是要使用其直接API开始和提交。 如果您使用的是容器管理的EntityManager,则自动意味着您必须使用JTA EntityManager 。 如果您使用的是应用程序管理的EntityManager,则可以使用JTA或本地资源。 在现实生活中,这意味着,如果您使用的是JTA EntityManager,则您只需照顾更高级别的事务管理:

  • 声明性地 使用注释或XML JTA交易属性,或
  • 以编程方式 使用javax.transaction.UserTransaction

如果您使用的是本地资源EntityManager,则需要更深入一点,并使用EntityManager.getTransaction()返回javax.persistence.EntityTransaction并调用commit(-)begin(-)rollback()等。使用transaction-type属性在persistence.xml定义此功能:

<?xml version='1.0' encoding='UTF-8'?>
<persistence ...><persistence-unit transaction-type='RESOURCE_LOCAL' ... >
</persistence>

另一个可能的值(当未定义transaction-type时为默认值)是JTA

Java EE中由应用程序管理的JTA EntityManager

尽管这个字幕听起来很复杂,但了解EntityManager和PersistenceContexts的所有先前类型后,您应该确切了解if指的是什么。

  • “应用程序托管”意味着我们将注入@PersistenceUnit EntityManagerFactory而不是EntityManager,
  • 之所以称为 “ Java EE”,是因为这些示例(在github上发布)仅在Java EE Application Server中使用
  • “ JTA”,因为我们将使用JTA事务级别,因此不会使用javax.persistence.EntityTransaction

现在,您需要意识到的第一件事是如何使用JTA事务。 JTA事务管理有两种类型-容器(CMT)和Bean管理(BMT)。 容器管理的JTA事务CMT )意味着您使用javax.ejb.TransactionAttribute定义tx是否应处于活动状态以及事务边界在何处。 这是默认的JTA管理类型。 或者,您可以选择自己划定JTA事务的边界。 这称为Bean管理的JTA事务BMT )。应用程序(您)负责启动,回滚或提交事务。 您如何控制JTA交易? 您可以使用javax.transaction.UserTransaction做到这一点。

您如何获得一个? 好吧,至少有3种方法可以做到这一点:

  • 它绑定到组件私有名称空间( java:comp/UserTransaction )中的JNDI,因此您可以使用InitialContextSessionContext对其进行查找,
  • 您可以使用SessionContext进行访问– SessionContext#getUserTransaction()
  • 因为它绑定在众所周知的JNDI名称中,所以您可以让容器使用以下方式注入它: @Resource UserTransaction utx;

如果您具有UserTransaction ,则可以开始划分事务中要执行的内容。 注意,您仍在控制JTA事务 -您甚至都没有接触EntityManager的资源本地事务。

EntityManager何时在JTA事务中?

如果没有前面的介绍,您可能会认为由应用程序管理的EntityManager意味着您将自己承担一切–创建,共享EntityManager,开始tx,提交,关闭。 但是,了解了以上所有差异后,您知道可以在应用程序管理的EntityManager中使用JTA事务 。 但是问题是–如何使它知道活动的JTA事务? 如果我们有一个由容器管理的EntityManager,我们知道容器将全部管理该容器,但是如果我们独自一人–我们该怎么做? 实际上, 这取决于我们在哪里创建EntityManager 。 在下面找到一些示例(完整的代码可以在我的github帐户上找到:

情况1:我们在没有活动交易的情况下调用以下代码(因此,对于CMT,我们具有TransactionAttribute.NEVERTransactionAttribute.NOT_SUPPORTED ;对于BMT,我们不调用UserTransaction.begin()

EntityManager em = emf.createEntityManager();
em.persist(new Customer(firstName, lastName));

结果: EntityManager操作在持久化时不会引发任何异常,但是所有更改都不会提交 。 没有活动的事务,因此不会进行任何更改。

情况2:我们使用BMT调用以下代码:

utx.begin();EntityManager em = emf.createEntityManager();em.persist(new Customer(firstName, lastName));utx.commit();

结果:在JTA提交期间,新数据已正确保留(在最后一行。)

情况3:我们使用BMT调用以下代码:

EntityManager em = emf.createEntityManager();
utx.begin();em.persist(new Customer(firstName, lastName));utx.commit();

结果: EntityManager在事务之外,因为它是在启动JTA事务之前创建的。 尽管已提交JTA事务,但更改不会持久保存。 没有异常被抛出。

在第二个示例的情况下,您可能会问自己–是否可以首先创建EntityManager,然后开始事务,最后以某种方式使EntityManager知道周围的TX? 如果事实是这样,则可以执行此操作,而这正是EntityManager#joinTransaction()方法的用途。 以下两种情况将向您展示如何使用它:

情况4:我们使用BMT调用以下代码:

EntityManager em = emf.createEntityManager();
utx.begin();
em.joinTransaction();em.persist(new Customer(firstName, lastName));utx.commit();

结果:在这里,我们明确地告诉EntityManager加入活动的JTA事务。 结果, EntityManager将在JTA commit期间刷新其所有更改

情况5:我们使用BMT调用以下代码:

EntityManager em = emf.createEntityManager();
utx.begin();em.joinTransaction();em.persist(new Customer(firstName, lastName));utx.commit();utx.begin();em.joinTransaction();em.persist(new Customer(firstName, lastName));utx.commit();

结果: 两个EntityManager操作都正确存在。 在这里,我们证明了应用程序管理的持久性上下文可以跨越多个JTA事务 (请注意,我们没有创建另一个EntityManager,而只是重用了先前事务中使用的那个)。在这里,您可以看到JPA规范(JPA规范) 2.0最终版本)告诉您有关应用程序管理的持久性上下文的信息:

7.7应用程序管理的持久性上下文

使用JTA应用程序管理的实体管理器时,如果实体管理器在当前JTA事务的范围之外创建,则应用程序有责任通过调用EntityManager.joinTransaction将实体管理器与事务关联(如果需要)。 。 如果实体管理器是在JTA事务范围之外创建的,则除非调用EntityManager.joinTransaction,否则它不与事务关联。
使用CDI共享EntityManager

如前所述,如果要在组成一个事务的组件之间共享EntityManager,则应手动传递它(毕竟,它是“应用程序管理的”。)CDI可能是此处的解决方案。 您可以生成请求范围的EntityManager并将其注入所需的任何组件中。 看起来可能像这样(在现实生活中,您还需要注意处理EM):

public class Resources {@PersistenceUnitEntityManagerFactory emf;@Produces @RequestScopedpublic EntityManager createEntityManager() {return emf.createEntityManager();}
}

现在,在每个bean中我们都可以拥有:

@Stateless
public class MyBean {@InjectEntityManager em;
}

在构成事务的不同组件之间共享应用程序管理的持久性上下文似乎是一种非常干净的方法。 但是,我担心的是:知道由应用程序管理的EntityManager事务性行为取决于创建它的位置 ,因此这种方法有时可能会给您带来讨厌的结果。 以以下代码为例(在我的Github项目中也可以找到该类, 此处正是该类):

@Stateless
@TransactionAttribute(TransactionAttributeType.NEVER)
public class BeanABoundary {@Injectprivate EntityManager em;@EJBBeanB beanB;public void invoke() {em.getProperties();beanB.invoke();
}

请注意,BeanA是非事务性资源。 还要注意,我们在EntityManager上注入并调用了一些操作 (这使得注入实际上得以执行。)现在,如果BeanB是事务性的,并且也注入并使用EntityManager –我们将以不会进行抛出的非事务性EntityManager结尾任何异常,并且不会将任何更改保存到数据库

在旧的@PersistenceContext的情况下,我们将处于事务中,因为EntityManager将由容器管理,并且容器将知道当前处于活动状态的事务。 容器负责在事务边界之间共享EntityManager。 在显示CDI生产者方法的情况下,CDI不知道运行事务,而只是共享EntityManager。

当然,可以使用CDI并创建一个@Produces @PersistenceContext EntityManager em ,然后使用@Inject EntityManager 。 这将与@PersistenceContext EntityManager完全一样,但是允许我们在生成EntityManager的单个位置定义(例如)持久性单元的名称。 但是,如果我们要拥有一个应用程序管理的EntityManager,则这不是一个选择。

参考: 实体管理器的类型:由我们的JCG合作伙伴 Piotr Nowicki在Piotr Nowicki主页博客上进行的应用程序管理的EntityManager 。

翻译自: https://www.javacodegeeks.com/2013/03/types-of-entity-managers-application-managed-entitymanager.html

实体管理器的类型:应用程序管理的EntityManager相关推荐

  1. entitymanager_实体管理器的类型:应用程序管理的EntityManager

    entitymanager JPA规范定义了几种类型的EntityManagers / Persistence Context. 我们可以有: 扩展和事务范围的EntityManager, 容器管理或 ...

  2. pyqt 控件焦点_PyQt5(2)——调整布局(布局管理器)第一个程序

    我们拖拽一个UI文件,转为PY文件后生成一个类Ui_MainWindow 此时,我们新建一个文件,用来控制业务逻辑(继承界面中的类),跟界面分开,这样我们就完成了界面和逻辑相分离(这段代码使用率基本1 ...

  3. Android布局管理器-使用TableLayout表格布局管理器实现简单的用户登录页面

    场景 Android布局管理器-使用FrameLayout帧布局管理器显示层叠的正方形以及前景照片: https://blog.csdn.net/BADAO_LIUMANG_QIZHI/article ...

  4. java中布局管理器flowlayout_JAVA基础:FlowLayout布局管理器

    在前面的例子中,使用到了FlowLayout布局管理器.FlowLayout型布局管理器对容器中组件进行布局的方式是将组件逐个地安放在容器中的一行上.一行放满后就另起一个新行. FlowLayout有 ...

  5. 引用管理器没有程序集_程序员必背英语单词不会,就别说你是程序员!

    Compile:编绎 Run:运行 Class:类 Object:对象 System:系统 out:输出 print:打印 line:行 variable:变量 type:类型 static:静态的 ...

  6. win10 系统下本地 IIS 管理器 MIME 类型添加

    问题: 我在本地建了一个本地的 web 服务器,如下图所示: 我在里面放了一些文件,点击其他文件都可以下载到本地,可是点击 *.xbin 类型的文件,就会出现如下提示: 原因: *.xbin 格式的文 ...

  7. Linux软件管理器(如何使用软件管理器来管理软件)

    我们的Linux系统大部分都是某个Linux厂商的系统,所以这些厂商可以编译好一些软件来提供用户下载,用户下载完了之后就可以直接安装,从而省去了编译源码及其过程中的各种问题.这时我们就可以使用相应的软 ...

  8. Android布局管理器-使用FrameLayout帧布局管理器显示层叠的正方形以及前景照片

    场景 Android布局管理器-使用LinearLayout实现简单的登录窗口布局: https://blog.csdn.net/BADAO_LIUMANG_QIZHI/article/details ...

  9. 黑莓桌面管理器4.2_虚拟桌面管理器行业现状调研分析及发展趋势预测报告(2020)...

    QYResearch预测:2020-2026全球与中国虚拟桌面管理器市场现状及未来发展趋势 [纸版价格]:RMB 18000 [电子版(PDF)价格]:RMB 18000 [报告篇幅]:101 [报告 ...

最新文章

  1. C# 继承实现父类方法、重写、重载
  2. 苹果电脑安装python-mac电脑安装python
  3. 【Android 逆向】Android 系统文件分析 ( /system/ 系统命令和系统应用数据目录 | /system/app/ 系统应用目录 | sys Linux 系统内核文件目录 )
  4. brew 无法安装iterm2_Mac系统iTerm2+oh-my-zsh配置及常用插件
  5. 【OpenCV3】Opencv3.2.0在Hisi3521下的交叉编译和移植
  6. boost::mp11::mp_invoke_q相关用法的测试程序
  7. 原来C语言还可以这样实现“泛型编程”!
  8. python参数估计置信区间_python中分布参数的置信区间估计
  9. 一文理解设计模式之--策略模式(Strategy)
  10. 全世界到底有多少软件开发人员?
  11. 台式机双系统安装(windows10+ubuntu18.04)及ROS安装的坑点解决
  12. 如何重置华为交换机初始密码?
  13. 愿你我,能被这世界温柔以待
  14. 等保2.0三级通用要求
  15. Robocup3D优化任务布置
  16. Apktool命令使用总结
  17. stm32 IAP 程序编写心得
  18. len计算机语言,python中len的使用方法
  19. java四大名著知乎_给四大名著重新取名……从知乎热帖看畅销书起名套路
  20. JS微信打飞机游戏(一)

热门文章

  1. java速学_5分钟快速入门Java,不看真的可惜了
  2. ReviewForJob(3)表、栈和队列
  3. XML——生成 XML 文档(读入 XML的反向过程)
  4. selenium 替代品_每个人都在谈论Selenium替代品-明智地选择!
  5. java模拟连接超时_Java:使用Toxiproxy模拟各种连接问题
  6. portlet_平台策略:从Portlet到OpenSocial小工具再到渐进式Web应用程序:最新技术
  7. jvm高并发_JVM上的高并发HTTP客户端
  8. java常见的ide_在三个Java IDE中生成的三种常见方法
  9. Java:如何创建轻量级数据库微服务
  10. 记录更新(Java数据类)