JPA EntityManager 详解

持久化上下文(Persistence Contexts)的相关知识,内容包括如何从Java EE容器中创建EntityManager对象、如何从Java SE中创建EntityManager对象、持久化上下文与事务(Transction)的关系,以及实体管理器工厂(Entity Manager Factory)的相关内容。
通过本章的学习,读者将深入掌握JPA中有关持久化上下文、事务处理的相关知识,从而能够更加深入地应用JPA。


11.1 获得EntityManager对象

那么如何获得EntityManager对象呢?这又是JPA中另外一个很重要的问题。


11.1.1 Java EE环境与J2SE环境

在详细讲述EntityManager对象之前,读者首先要分清楚两个概念,即Java EE环境与J2SE环境。因为在本章后面的学习中要经常提到这两个概念,所以读者一定要先理解它们,为以后的学习打好基础。


— Java EE环境,包括EJB容器和Web容器。

(1)Web容器:只运行Web应用的容器,例如Tomcat就是开源的Web容器,它可以运行JSP、Servlet等。

(2)EJB容器:运行在EJB组件的容器,提供EJB组件的状态管理、事务管理、线程管理、远程数据资源访问、连接管理和安全性管理等系统级服务。例如JBoss为EJB容器和Web容器(Web容器是集成了Tomcat)结合。

部署在EJB容器中的JAR包都可以认为是运行在EJB容器中。但JBoss中的Web应用,比如war包中的类就不是运行在EJB容器中,而是运行在Web容器中。

— J2SE环境

最普通Java运行环境,例如一个HelloWorld的Java程序就是运行在J2SE的环境中,通常使用main入口方法作为程序启动的触发。

如图11-1所示,它说明了Java EE与J2SE环境的关系。

11.1.2 两种类型的EntityManager对象

根据EntityManager对象的管理方式,可以有以下两种类型。

— 容器托管的(container-managed)EntityManager对象

容器托管的EntityManager对象最简单,程序员不需要考虑EntityManager连接的释放,以及事务等复杂的问题,所有这些都交给容器去管理。容器托管的EntityManager对象必须在EJB容器中运行,而不能在Web容器和J2SE的环境中运行。本书前面讲述的EntityManager对象都是通过注入 @PersistenceContext注释来获得的,其实,这种获得EntityManager对象的方式就是容器托管的。

— 应用托管的(application-managed)EntityManager对象

应用托管的EntityManager对象,程序员需要手动地控制它的释放和连接、手动地控制事务等。但这种获得应用托管的EntityManager对象的方式,不仅可以在EJB容器中应用,也可以使 JPA脱离EJB容器,而与任何的Java环境集成,比如说Web容器、J2SE环境等。所以从某种角度上来说,这种方式是JPA能够独立于EJB环境运行的基础。

理想状态下,最好是选用容器托管的EntityManager对象的方式,但在特殊的环境下,还是需要使用应用托管的EntityManager对象这种方式。

正是因为应用托管的EntityManager对象的连接释放、事务控制比较复杂,所以在使用时涉及的相关内容比较多,这些内容将在本章后面部分详细讲述,这里读者应对两种方式有一个大致的了解,两种EntityManager对象类型的比较如表11-1所示。

表11-1 容器托管与应用托管的EntityManager对象对比

比较内容

容器托管的(container-managed)EntityManager对象

应用托管的(application-managed)EntityManager对象

获得方式

两种方式:1 @PersistenceContex注入 2 JNDI获得

EntityManagerFactory创建

支持事务

JTA

JTA、RESOURCE_LOCAL

运行环境

EJB容器

EJB容器、Web容器、J2SE环境

11.1.3 容器托管的(container-managed)EntityManager对象

容器托管的EntityManager对象只能运行在EJB容器中。所以可以这样理解,只有在EJB-JAR包中,才可以获得容器托管的EntityManager对象,否则只能获得应用托管的EntityManager对象。

在EJB容器中获得EntityManager对象主要有两种方式,即@PersistenceContext注释注入和JNDI方式获得。

11.1.3.1 通过@PersistenceContext注释注入

这种方式获得EntityManager对象最为常用,例如下面代码所示。

@Stateless

public class CustomerService implements ICustomerService {

@PersistenceContext(unitName = "jpaUnit")

private EntityManager entityManager;

public List<CustomerEO> findAllCustomers() {

Query query = entityManager.createQuery("SELECT c FROM CustomerEO c");

List<CustomerEO> result = query.getResultList();

for (CustomerEO c : result) {

System.out.println(c.getId()+","+c.getName());

}

return result;

}

}


在使用此种方式创建EntityManager对象时,需要注意以下几个问题。

— @PersistenceContext注释中,其中unitName为persistence.xml文件中<persistence-unit>元素中的属性“name”的值,表示要初始化哪个持久化单元,如下所示。

<persistence>

<persistence-unit name="jpaUnit" transaction-type="JTA">

</persistence-unit>

</persistence>


— @PersistenceContext注释中还可以配置其他的设置,它的定义如下所示。

@Target({TYPE, METHOD, FIELD}) @Retention(RUNTIME)

public @interface PersistenceContext{

String name() default "";

String unitName() default "";

PersistenceContextType type default TRANSACTION;

PersistenceProperty[] properties() default {};

}


— 其中PersistenceContextType可以设置创建EntityManager对象时,持久化上下文的作用范围,它的意义在于对有状态的Bean(Stateless Bean)可以跨事务操作实体。它主要有两种方式,定义如下所示。

public enum PersistenceContextType {

TRANSACTION,

EXTENDED

}


默认情况下使用TRANSACTION,有关TRANSACTION方式和EXTENDED方式创建EntityManager对象的异同,将在下文中详细讲述,这里读者简单了解一下即可。

11.1.3.2 通过JNDI的方式获得

如果指定了@PersistenceContext注释中的name值,则设置了持久化上下文的JNDI名称。通过SessionContext可以创建EntityManager对象。

例如,下面代码为通过JNDI方式获得EntityManager对象。

@Stateless

@PersistenceContext(name="jpa")

public class CustomerService implements ICustomerService {

@Resource

SessionContext ctx;

public List<CustomerEO> findAllCustomers() {

EntityManager entityManager = (EntityManager) ctx.lookup("jpa");

Query query = entityManager.createQuery("SELECT c FROM CustomerEO c");

List<CustomerEO> result = query.getResultList();

for (CustomerEO c : result) {

System.out.println(c.getId()+","+c.getName());

}

return result;

}

}


11.1.4 应用托管的(application-managed)EntityManager对象

应用托管的EntityManager对象,不仅可以在Java EE环境中获得,也可以应用在J2SE的环境中。但无论是在什么情况下获得的EntityManager对象,都是通过实体管理器工厂(EntityManagerFactory)对象创建的。所以如何获得应用托管的EntityManager对象关键是 EntityManagerFactory对象如何获得。

下面就分别讲述在EJB容器、Web容器和J2SE环境中如何获得EntityManagerFactory对象。

11.1.4.1 EJB容器中获得

在EJB容器中,EntityManagerFactory对象可以通过使用注入@PersistenceUnit注释获得,例如下面代码为在EJB容器中,获得应用托管的EntityManager对象的方法。

@Stateless

public class CustomerService implements ICustomerService {

@PersistenceUnit(unitName="jpaUnit")

private EntityManagerFactory emf;

public List<CustomerEO> findAllCustomers() {

/**创建EntityManager对象*/

EntityManager em = emf.createEntityManager();

Query query = em.createQuery("SELECT c FROM CustomerEO c");

List<CustomerEO> result = query.getResultList();

for (CustomerEO c : result) {

System.out.println(c.getId()+","+c.getName());

}

/**关闭EntityManager */

em.close();

return result;

}

}

通过以上的EntityManager对象代码,可以总结出以下几个问题。

— 应用托管的EntityManager对象,要在代码中手动地创建和关闭,例如下面代码所示。

EntityManager em = emf.createEntityManager();

/**其他的业务逻辑*/

em.close();

这点正是与容器托管的EntityManager对象的最大不同之处。事实上,容器托管的EntityManager对象,它的创建和关闭是由容器负责管理的,所以不需要编写代码来控制。

— 应用托管的EntityManager对象,都是通EntityManagerFactory对象来创建的。在容器中可以通过使用注入@PersistenceUnit注释的方法实现,它的定义如下所示。

@Target({TYPE, METHOD, FIELD}) @Retention(RUNTIME)

public @interface PersistenceUnit{

String name() default "";

String unitName() default "";

}


其中,属性unitName为persistence.xml文件中<persistence-unit>元素中的属性“name”的值,表示要初始化哪个持久化单元,与@PersistenceContext注释中unitName属性相同。

11.1.4.2 Web容器中获得

在Web容器中,EntityManagerFactory对象也可以通过使用注入@PersistenceUnit注释获得。例如,下面代码为在Servlet中,获得应用托管的EntityManager对象的方法。

public class TestServlet extends HttpServlet {

@PersistenceUnit(unitName = "jpaUnit")

private EntityManagerFactory emf;

public TestServlet() {

super();

}

public void doGet(HttpServletRequest request, HttpServletResponse response)

throws ServletException, IOException {

doPost(request, response);

}

public void doPost(HttpServletRequest request, HttpServletResponse response)

throws ServletException, IOException {

response.setContentType("text/html");

PrintWriter out = response.getWriter();

out.println("<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.01 Transitional //EN\">");

out.println("<HTML>");

out.println(" <HEAD><TITLE>A Servlet</TITLE></HEAD>");

out.println(" <BODY>");

if (emf != null) {

/**创建EntityManager 对象*/

EntityManager entityManager = emf.createEntityManager();

try {

Query query = entityManager

.createQuery("SELECT c FROM CustomerEO c");

List<CustomerEO> result = query.getResultList();

for (CustomerEO c : result) {

System.out.println(c.getId() + "," + c.getName());

}

} finally {

/**关闭EntityManager*/

entityManager.close();

}

}

out.println(" </BODY>");

out.println("</HTML>");

out.flush();

out.close();

}

}


由于是通过注入方法获得的EntityManagerFactory对象,所以EntityManagerFactory对象的创建不需要手动创建和关闭,这里与在EJB容器中的获得方法相同。

★ 提示 ★

目前JBoss 4.2集成了的Tomcat版本为5.5,但Tomcat 6.0以后的版本中才支持使用注释,所以如果将本例中Servlet运行在JBoss 4.2中,并不能获得EntityManagerFactory对象;但在符合J2EE 5.0的服务器中,这样运行是可以的。

虽然在目前JBoss 4.2版本中不支持使用注释,但可以通过另一种方式来获得应用托管的EntityManager对象。代码如下所示。

public class TestServlet extends HttpServlet {

private EntityManagerFactory emf;

public TestServlet() {

super();

}

public void doGet(HttpServletRequest request, HttpServletResponse response)

throws ServletException, IOException {

doPost(request, response);

}

public void doPost(HttpServletRequest request, HttpServletResponse response)

throws ServletException, IOException {

response.setContentType("text/html");

PrintWriter out = response.getWriter();

out.println("<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.01 Transitional //EN\">");

out.println("<HTML>");

out.println(" <HEAD><TITLE>A Servlet</TITLE></HEAD>");

out.println(" <BODY>");

if (emf != null) {

/**创建EntityManager 对象*/

EntityManager entityManager = emf.createEntityManager();

try {

Query query = entityManager

.createQuery("SELECT c FROM CustomerEO c");

List<CustomerEO> result = query.getResultList();

for (CustomerEO c : result) {

System.out.println(c.getId() + "," + c.getName());

}

} finally {

/**关闭EntityManager*/

entityManager.close();

}

}

out.println(" </BODY>");

out.println("</HTML>");

out.flush();

out.close();

}

/**Servlet初始化时,创建EntityManagerFactory 对象*/

public void init() throws ServletException {

if (emf == null) {

emf = Persistence.createEntityManagerFactory("jpaUnit");

}

}

/**Servlet销毁时,关闭EntityManagerFactory对象*/

public void destroy() {

if (emf.isOpen())

emf.close();

}

}


使用这种方式创建EntityManagerFactory对象需要注意以下几个问题。

— 可以看到,这里的EntityManagerFactory对象不是通过注入获得的,而是通过Persistence类中的静态方法createEntityManagerFactory来创建的。

— 正因为EntityManagerFactory对象是手动创建的,所以在不再使用时,一定要调用close()方法手动关闭。

11.1.4.3 J2SE环境中获得

在J2SE环境中,获得应用托管的EntityManager对象只能通过手动创建的方式,而不能使用注释的方式,与Web容器中不使用注释的方法相同,都是通过Persistence类中createEntityManagerFactory来创建的。

例如,下面代码为J2SE环境中获得应用托管EntityManager对象的方法。

public class CustomerClient {

public static void main(String[] args) {

/** 创建EntityManagerFactory对象 */

EntityManagerFactory emf = Persistence

.createEntityManagerFactory("jpaUnit");

/** 创建entityManager对象 */

EntityManager entityManager = emf.createEntityManager();

Query query = entityManager.createQuery("SELECT c FROM CustomerEO c");

List<CustomerEO> result = query.getResultList();

for (CustomerEO c : result) {

System.out.println(c.getId() + "," + c.getName());

}

/** 关闭entityManager对象 */

entityManager.close();

/** 关闭EntityManagerFactory对象 */

emf.close();

}

}

但是,在J2SE环境中使用JPA需要将实现的JPA的第三方类包和数据库的驱动包,设置到当前的运行环境下。

例如,在Eclipse中创建一个Java项目,需要将JPA实现者的类库(这里以Hibernate为例)和MySQL的数据库连接包添加到构建路径中,如图11-2所示。

11.1.5 ThreadLocal的使用

对于在Web容器中使用EntityManager对象,这里需要做一些改进,才能更安全。读者应该了解,Servlet是非线程安全的,所以需要改变获得EntityManager对象的方式,这里笔者建议使用ThreadLocal类。

ThreadLocal就是为每一个使用某变量的线程都提供一个该变量值的副本,使每一个线程都可以独立地改变自己的副本,而不会和其他线程的副本冲突。从线程的角度看,就好像每一个线程都完全拥有一个该变量,这就解决了Servlet非线程安全的问题。

首先编写一个EntityManagerHelper类,代码如下所示。

public class EntityManagerHelper {



private static final EntityManagerFactory emf;

private static final ThreadLocal<EntityManager> threadLocal;



/**初始化*/

static {

emf = Persistence.createEntityManagerFactory("jpaUnit");

threadLocal = new ThreadLocal<EntityManager>();

}



/**通过threadLocal 获得EntityManager 对象*/

public static EntityManager getEntityManager() {

EntityManager manager = threadLocal.get();

if (manager == null || !manager.isOpen()) {

manager = emf.createEntityManager();

threadLocal.set(manager);

}

return manager;

}



/**关闭EntityManager 对象*/

public static void closeEntityManager() {

EntityManager em = threadLocal.get();

threadLocal.set(null);

if (em != null) em.close();

}



public static void beginTransaction() {

getEntityManager().getTransaction().begin();

}



public static void commit() {

getEntityManager().getTransaction().commit();

}



public static Query createQuery(String query) {

return getEntityManager().createQuery(query);

}



}


这样经过改进后,在Servlet中创建EntityManager对象的方法修改为如下所示。

public class TestServlet extends HttpServlet {

public TestServlet() {

super();

}

public void doPost(HttpServletRequest request, HttpServletResponse response)

throws ServletException, IOException {

EntityManager entityManager = EntityManagerHelper.getEntityManager();

try {

Query query = entityManager

.createQuery("SELECT c FROM CustomerEO c");

List<CustomerEO> result = query.getResultList();

for (CustomerEO c : result) {

System.out.println(c.getId() + "," + c.getName());

}

} finally {

/**关闭EntityManager*/

EntityManagerHelper.closeEntityManager();

}

}

}



http://ajava.org/readbook/J2EE/ejbjpa/12472.html
EntityManager API方法详解 Session bean or MD bean对Entity bean的操作(包括所有的query, insert, update, delete操作) 立即下载

相关推荐

电子发票二维码背后的秘密:10分钟看懂校验码、加密字符含义与防伪设计

本文深入解析电子发票二维码的结构与防伪设计,揭示校验码和加密字符的生成原理及验证方法。通过实际案例和技术细节,帮助财务人员理解电子发票的安全机制,提升防伪识别能力,确保税务合规。

weixin_29248611的博客 530

JPA - EntityManager详解

【1】EntityManager介绍在 JPA 规范中, EntityManager 是完成持久化操作的核心对象。实体作为普通 Java 对象,只有在调用 EntityManager 将其持久化后才会变成持久化对象。EntityManager 对象在一组实体类与底层数据源之间进行 O/R 映射的管理。它可以用来管理和更新 Entity Bean, 根椐主键查找 Entity Bean, 还可以通过J

小小默:进无止境 3万+

服务器卡死排查实战:从现象分类到根因定位的完整手册

服务器卡死是运维中最令人头疼的故障之一,从游戏圈吐槽的“土豆服务器”到生产环境中的Linux系统无响应、rsync复制挂起,本质都是系统或进程失去正常响应能力。其原理通常涉及CPU、内存、磁盘IO或网络资源耗尽,以及内核和驱动异常。掌握系统化的排查方法,能够帮助工程师快速定位根因、缩短故障时间,避免盲目重启。本文从资源、层级、场景等多维度分类,结合top、dmesg、strace等工具,梳理一套从现象确认、指标收集、日志分析到进程定位的实战排查流程,并覆盖常见高频场景与预防治理建议。无论你是运维新手还是老手

weixin_33851177的博客 375

JPA 之 Hibernate EntityManager 使用指南

JPA 之 Hibernate EntityManager 使用指南

墨鸦的博客 2万+

SpringBoot实战(二十八)集成 Collabora Online 实现在线编辑

SpringBoot实战(二十八)集成 Collabora Online 实现在线编辑

ACGkaka的博客 6984

R语言下载包报错?可能是IE浏览器在搞鬼!手把手教你修复(附CRAN镜像选择指南)

本文深入解析了R语言下载包时常见的网络报错问题,特别是Windows系统中因Internet Explorer代理设置导致的连接失败。文章提供了从重置IE配置、排查防火墙到优化CRAN镜像选择的完整解决方案,并附有详细的配置指南和自动化诊断脚本,帮助用户彻底解决R包安装难题。

weixin_29056781的博客 742

Spring Data JPA 从入门到精通~EntityManager介绍

EntityManager 介绍 我们前面已经无数次提到了,JPA 的默认 Repository 的实现类是 SimpleJpaRepository,而里面的具体实现就是调用的 EntityManager。对于 javax.persistence.EntityManager 通过源码,先来看下它主要给我们提供了哪几个方法: public interface EntityManager { /** *根据主键查询实体对象 */ public <T> T find(Cl

小强快跑~~ 3277

完美解决unknown failed to transfer from http://0.0.0.0/ during a previous attempt的错误

完美解决unknown failed to transfer from http://0.0.0.0/ during a previous attempt的错误

念兮为美 2279

JPA EntityManager详解

持久化上下文(Persistence Contexts)的相关知识,内容包括如何从Java EE容器中创建EntityManager对象、如何从Java SE中创建EntityManager对象、持久化上下文与事务(Transction)的关系,以及实体管理器工厂(Entity Manager Factory)的相关内容。 通过本章的学习,读者将深入掌握JPA中有关持久化上下文、事务处理的相关知

张晓 2251

Android Audio音量——音频类型新增(九)

在实际开发中,经常会遇到需要新增一个音频类型(usage)的需求,这里我们简单介绍一下需要修改的代码。

小旭的专栏 1570

AI 时代嵌入式工程师的能力模型与学习路线:全系列收官

AI 时代嵌入式工程师的能力模型与学习路线:全系列收官

weixin_42162924的博客 36

JPA EntityManager接口详解

分享知识 传递快乐 在上章的后面我们已经讲了JPA与Hibernater的之间的联系,接下我们谈谈JPA的常用操作。 常用Hibernate的小伙伴都熟悉要想获取数据库数据,通常会用到SessionFactory和Session两个接口下的方法来获取数据。而在SpringBoot+Hibernate整合用的则是JPA操作规范。 使用JPA规范是不能用@Autowired直接注入Sess...

旷野历程 1847

hwasan / asan详细分析踩内存之一:Use after free

UAF漏洞全称为use after free ,即利用已经被free掉的堆块被再次利用,该漏洞的存在是因为程序编写者在free堆块部分没有将该堆块的fd指针改为0,进而导致该堆块可以被申请回来,3.内存块被free后,其对应的指针没有被设置为 NULL,但是在它下一次使用之前,有代码对这块内存进行了修改,那么当程序再次使用这块内存时,就很有可能会出现奇怪的问题。2.堆块free后,对应指针没有被设置为NULL,即还可以调用会该堆块,当我们申请一个比该堆块小于等于的size时。

1398

jpa 托管_JPA EntityManager详解(一)

JPA EntityManager详解(一)持久化上下文(Persistence Contexts)的相关知识,内容包括如何从Java EE容器中创建EntityManager对象、如何从Java SE中创建EntityManager对象、持久化上下文与事务(Transction)的关系,以及实体管理器工厂(Entity Manager Factory)的相关内容。通过本章的学习,读者将深入掌握J...

weixin_39948442的博客 505

SIMATIC S7-1200, S7-1500 PID 控制[手册]

SIMATIC S7-1200, S7-1500 PID 控制[手册]

IDEA的使用指南

IDEA基于java的使用手册,可以最快速的上手,在使用中不断的丰富自己的使用技巧.

jpa transaction 回滚_JPA核心接口EntityManager API功能详解(二)

JPA入门精要系列:(1):JPA框架组件核心组成(2):EntityManager概要及API一览表本文由牛旦教育原创出品,欢迎收藏、点赞、分享。转载请注明来源@牛旦教育IT课堂1.1常用方法详解1.1.1 void persist(java.lang.Object entity)本方法的主要功能,是实现有效实体对象的持久化,即对实例托管并持久化到数据库。参数:entity,为用户定义的实体实例...

weixin_33350741的博客 446

visio安装包

Microsoft Office Visio 是一款专业的制图软件。利用经过更新的形状、协作工具和数据链接图表,创建专业级图表以简化复杂的信息。

JPA EntityManager详解(一)

持久化上下文(Persistence Contexts)的相关知识,内容包括如何从Java EE容器中创建EntityManager对象、如何从Java SE中创建EntityManager对象、持久化上下文与事务(Transction)的关系,以及实体管理器工厂(Entity Manager Factory)的相关内容。  通过本章的学习,读者将深入掌握JPA中有关持久化上下文、事务处理的相关

liruichuan的专栏 3195

pscad IEEE标准系统搭建说明

pscad IEEE标准系统搭建说明,包含典型的IEEE 9节点、14节点、30节点、39节点和118节点系统。内含标准测试系统的原始数据和潮流结果。

jpa 托管_JPA EntityManager详解

packagecom.idea.repository.impl;importjava.math.BigDecimal;importjava.math.BigInteger;importjava.util.Collections;importjava.util.List;importjava.util.Map;importjavax.persistence.EntityManager;importj...

weixin_39687667的博客 208

JPA -- EntityManager常用API详解

            实体状态和转换  实体状态详解Ø  临时状态: 实际上就是new了一个普通的JavaBean对象。Ø  托管状态 临时状态在调用persist()后,即可将一般的JavaBean做为了托管状态的Bean,该Bean的任何属性改动都会牵涉到数据库记录的改动。 一旦该记录flush到数据库之后,并且事务提交了,那么此对象不在持久化上下文中,即:变为了游离(没人管的孩子)状态了。...

YellowStar的博客 2万+
上一篇: EJB 3 初次学习小结
下一篇: JPA 泛型DAO 封装(源码来自EasyJWeb)
NationSoftware
博客等级 码龄18年 2粉丝 30原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值