`
zzc1684
  • 浏览: 1196188 次
  • 性别: Icon_minigender_1
  • 来自: 广州
文章分类
社区版块
存档分类
最新评论

操作EntityManager

阅读更多

操作EntityManager

Interacting with an EntityManager

现 在你已经学会如何部署和获取指向EntityManager的引用了,接下来你将学习如何正确地操作EntityManager。 EntityManager API包含了插入和删除实体的数据库操作方法,将游离的实体实例合并更新到数据库的方法。它还包含了一组丰富的查询API,你可以藉此来创建查询对象。

package javax.persistence;

public interface EntityManager {

   public void persist(Object entity);

   public <T> T find(Class <T> entityClass, Object primaryKey);

   public <T> T getReference(Class <T> entityClass, Object primaryKey);

   public <T> T merge(T entity);

   public void remove(Object entity);

   public void lock(Object entity, LockModeType lockMode);

   public void refresh(Object entity);

   public boolean contains(Object entity);

   public void clear();

   public void joinTransaction();

   public void flush();

   public FlushModeType getFlushMode();

   public void setFlushMode(FlushModeType type);

   public Query createQuery(String queryString);

   public Query createNamedQuery(String name);

   public Query createNativeQuery(String sqlString);

   public Query createNativeQuery(String sqlString, String resultSetMapping);

   public Query createNativeQuery(String sqlString, Class resultClass);

   public Object getDelegate();

   public void close();

   public boolean isOpen();

}

 

持久化实体

Persisting Entities

对 实体进行持久化就是将其插入到数据库中。你所持久化的是还未曾保存到数据库中的实体。要持久化一个实体,首先是为实体的实例分配内存,然后设置成员属性, 并设置好与其他对象可能存在的任何关联关系。换言之,你可以像操作普通Java对象那样初始化一个entity bean。一旦完成这一步,你就可以调用EntityManager.persist()方法来保存该实体了。

Custom cust = new Customer();

cust.setName("Bill");

entityManager.persist(cust);

当 调用persist()方法后,EntityManager会将Customer添加到等待数据库插入的队列中,对象实例即处于托管状态。实际的插入操作 何时发生则取决于多种因素。如果在事务范围内调用了persist()方法,插入操作可能马上执行,也可能在事务提交时执行,这依赖于flush模式(本 章的后续部分会讲到)的取值。任何时候,你都可以通过调用flush()方法在一个事务内强制手工插入。当且仅当entity manager是extended persistence context时,你才可以在事务范围外调用persist()方法。此时,插入操作会被保存到队列中,直到persistence context与某个事务关联之后才被执行。一个由EJB容器注入的extended persistence context会自动与JTA事务关联。而对于通过EntityManagerFactory API手动创建的extended context,你必须调用Entity.Manager.joinTransaction()方法才能使之与事务关联。

如 果实体与其他实体存在任何关联关系,且正确设置了级联策略(cascade policies),关联实体同样可以被保存到数据库中。我们将在第7章讨论级联。在第6章里,我们还将看到当persist()方法被调用时,Java Persistence能够自动生成主键。因此在上例中,如果你启用了自动主键生成功能,在persist()方法执行完毕后,你将会看到生成的主键。

如 果传入 persist()方法的参数不是实体类型的,persist()方法将抛出Illegal- ArgumentException异常。在transaction-scoped persistence context里,事务范围外的persist()调用会引起TransactionRequiredException异常。而在extended persistence context中,事务范围外的persist()调用则是合法的;不过在persistence context与事务关联之前,数据库插入操作是不会被执行的。

查找实体

Finding Entities

EntityManager提供了两种在数据库中查找对象的机制:一种是使用entity manager提供的简单方法根据主键在数据库中查找实体,另一种则是创建查询对象并执行查询。

find()和getReference()方法

EntityManager提供了两个不同的方法允许你通过主键来查找实体。

public interface EntityManager {

   <T> T find(Class<T> entityClass, Object primaryKey);

   <T> T getReference(Class<T> entityClass, Object primaryKey);

}

 

这两个方法都接受实体的 class和代表实体主键的对象作为参数。由于它们使用了Java泛型方法,无需任何显示的类型转换即可获得特定类型的实体对象。那么,我们该如何区别使 用这两个方法呢?在无法从数据库中找到指定实体时,find()方法会返回null。它还会根据延迟加载策略(lazy-loading,详见第6章相关 讨论)初始化entity bean的内部状态。

Customer cust = entityManager.find(Customer.class, 2);

在 本例中,我们查找一个主键 ID值为2的Customer对象。find()方法期望第二个参数的类型为Object,而非上述的基本数据类型,那么它是怎么通过编译的呢?此处,我 们用到了Java 5的一个新特性,称作自动装箱(autoboxing),它将基本数据类型直接转换为相应的对象类型。因此,常量2实际上是被转换成了 java.lang.Integer类型。

Customer cust = null;

try {

   cust = entityManager.getReference(Customer.class, 2);

} catch (EntityNotFoundException notFound) {

   // 恢复逻辑

}

 

getReference() 方法与find()方法的不同之处在于:如果在数据库中找不到相应的实体,
getReference()方法将抛出 javax.persistence.EntityNotFoundException异常;
并且该方法并不保证返回实例的内部状态会被初始化。

如果传入的参数不是实体类型,find()方法和getReference()方法都会抛出
Illegal- ArgumentException异常。你可以在事务范围之外调用这两个方法,
其行为依据persistence context的不同而有所不同:
若EntityManager是transactionscoped persistence context,则会返回游离对象;
而若是extended persistence context,则返回托管对象。

查询

持久对象也可以通过EJB QL来查询。与EJB 2.1不同的是,此处不再有任何finder方法了,
你必须通过调用EntityManager的createQuery()、createNamedQuery()或createNativeQuery()方法
来创建Query对象进行查询。

 

public interface EntityManager {

   Query createQuery(String queryString);

   Query createNamedQuery(String name);

   Query createNativeQuery(String sqlString);

   Query createNativeQuery(String sqlString, Class resultClass);

   Query createNativeQuery(String sqlString, String resultSetMapping);

}

创建并执行EJB QL查询与创建并执行JBDC PreparedStatement非常相似。

Query query = entityManager.createQuery("from Customer c where id=2");

Customer cust = (Customer)query.getSingleResult();

 

我们将在第9章详细介绍查询和EJB QL。

所有由find(),getResource()或查询对象所返回的实体实例都将保持托管状态,直至其所在的persistence context被关闭为止。亦即,期间再次调用find()或者任何其他的方法,都将返回同样的实体对象实例。

更新实体

Updating Entities

一 旦你调用了find(),getReference(),或创建并执行了一次查询,所得的entity bean实例在persistence context关闭前仍将处于托管状态。在此期间,你可以像其他对象那样随便更改entity bean实例的状态,任何更改都将被自动(取决于flush模式)或手工(通过调用flush()方法)地同步到数据库中。

@PersistenceContext EntityManager entityManager;

@TransactionAttribute(REQUIRED)

public void updateBedCount(int id, int newCount) {

   Cabin cabin = entityManager.find(Cabin.class, id);

   cabin.setBedCount(newCount);

}

 

在这段代码中,persistence context一直与某个事务关联,因此find()方法返回的Cabin实例是受EntityManager托管的。亦即,你可以更改对象实例,一旦 EntityManager决定将更改从内存同步到数据库时,数据库便会被自动更新。

合并实体

Merging Entities

在Java Persistence中,你可以使用EntityManager的merge()方法,将游离实体的状态变更合并到数据库中。假设有一个远程Swing 客户端,它调用了TravelAgent session bean的远程方法,用以查找数据库中的cabin实体。

@PersistenceContext EntityManager entityManager;

@TransactionAttribute(REQUIRED)

public Cabin findCabin(int id) {

   return entityManager.find(Cabin.class, id);

}

 在本例中,由于findCabin()方法处于一个独立的JTA事务中,persistence context将在方法结束时被EJB容器关闭。当Cabin实例被序列化时,它会脱离entity manager的管理并被送到远程的Swing客户端。此时,该Cabin实例是一个普通的Java对象,并且不再关联于任何entity manager。你可以像对待普通Java对象那样,调用该对象的getters和setters。Swing客户端更改了这一Cabin实例的状态,然 后将其重新送回服务器。

Cabin cabin = travelAgent.findCabin(1);

cabin.setBedCount(4);

travelAgent.updateCabin(cabin);

TravelAgentBean.updateCabin()方法接受cabin实例作为参数,
并通过merge()方法将它合并到当前EntityManager管理的persistence context中。

@PersistenceContext EntityManager entityManager;

@TransactionAttribute(REQUIRED)

public void updateCabin(Cabin cabin) {

   Cabin copy = entityManager.merge(cabin);

}

 

由远程Swing客户端所作的修改将在EntityManager决定与数据库进行同步时被写回到数据库中。updateCabin()方法在合并cabin时遵循下列规则。

若 EntityManager未曾管理过与传入的cabin参数有着相同ID的Cabin实例,则 merge()方法会创建该参数的一份完整拷贝并将其作为方法的返回值。该份拷贝受entity manager管理,并且任何针对该份拷贝的setter方法调用所引起的状态更改,在EntityManager决定执行flush操作时,都会被同步 到数据库中。而传入的cabin参数仍将保持游离状态,不受托管。

若与传入的cabin参数有着相同主键的Cabin实例早已处于EntityManager的管理之中,则cabin参数的内容将被复制到托管的对象实例中。merge()方法将返回该托管

实例。而传入的cabin参数将仍然保持游离状态,不受托管。

同 样,如果传入merge()方法的参数不是实体类型,merge()方法将会抛出Illegal- ArgumentException异常;如果该方法在transaction-scoped persistence context范围外调用,则会引起TransactionRequiredException异常;而在extended persistence context中,事务范围外的merge()调用是允许的。但是,在persistence context重新与事务关联之前,更新操作都不会被同步到数据库中。

删除实体

Removing Entities

调 用EntityManager.remove()可以将实体从数据库中删除。不过,remove()方法并不立即生效,而是在EntityManager 决定执行flush操作时,根据定义好的flush规则(将在本章的后续部分讨论),才会执行SQL DELETE操作。

@PersistenceContext EntityManager entityManager;

@TransactionAttribute(REQUIRED)

public void removeCabin(int id) {

   Cabin cabin = entityManager.find(Cabin.class, id);

   entityManager.remove(cabin);

}

 

调用remove()方法之 后,cabin实例将不再受entity manager托管而成为游离对象如果其他实体对象与该对象存在关联关系,则这些对象也将依据级联规则(将在第7章中讨论)被相应删除。只有通过调用 persist()方法重建实体实例,remove()操作才可以被撤销(undone)。

传 入remove()方法的参数若不是实体类型,remove()方法将抛出IllegalArgument- Exception异常;如果该方法在transaction-scoped persistence context范围外调用,则会引起TransactionRequiredException异常;而在extended persistence context中,事务范围外的remove()调用是允许的。但是,在persistence context重新与事务关联之前,数据是不会从数据库中删除的。

refresh()

refresh()

如果发现当前受托管的实体并非数据库中的最新数据,你可以调用EntityManager. refresh()方法。refresh()方法会根据数据库的情况刷新内存中实体的状态,同时覆盖对实体所做的任何修改。

@PersistenceContext EntityManager entityManager;

@TransactionAttribute(REQUIRED)

public void refreshCabin(int id) {

   Cabin cabin = entityManager.find(Cabin.class, id);

   entityManager.refresh(cabin);

}

 

如果entity bean有关联实体,那么根据在实体映射元数据中设置的级联策略,那些关联实体也会被相应刷新。

传 入refresh()方法的参数若不是实体类型,refresh()方法将抛出IllegalArgument- Exception异常;在transaction-scoped persistence context范围外的refresh()调用则会引起TransactionRequiredException异常;而在extended persistence context中,事务范围外的remove()调用是允许的。如果需要刷新的实体对象在数据库中不存在(例如被其他线程或进程删除了),则会抛出 EntityNotFoundException异常。

contains()方法与clear()方法

contains() and clear()

contains()方法接受实体实例作为参数,如果该对象实例目前正受persistence context管理,则返回true。若该参数并非实体类型,则会抛出IllegalArgumentException异常。

你 可以使用EntityManager.clear()方法将persistence context中所有的托管实体都变成游离对象。需要注意的是,一旦你调用了clear()方法,对实体所做的任何修改都将被丢弃。因此,使用 clear()时需要格外小心。在调用clear()之前,先调用flush()方法以免丢失更改实为明智之举。

flush()方法和FlushModeType

flush() and FlushModeType

正 如上文所述,调用persist(),merge(),remove()方法之后,这些更改操作只有在 EntityManager决定执行flush操作时才会被同步到数据库中。你也可以在任何时候通过调用flush()方法做强行同步。缺省情况 下,flush操作会在相关查询执行之前和事务提交之时自动执行(一些低效的Java Persistence实现甚至可能会在任何查询执行之前都做flush操作)。但需注意的是,与一般查询不同,调用find()和 getReference()方法并不会引起flush。这是因为通过主键来查询实体是不会受任何更新操作的影响的。

可以通过枚举类型javax.persistence.FlushModeType来控制和修改这一默认行为。

public enum FlushModeType {

   AUTO,

   COMMIT

}

AUTO是前述的默认行为。COMMIT则表示,仅当事务提交时才对更改做flush操作,而

在任何查询执行之前都不会引发flush操作。你可以通过调用setFlushMode()方法来指定EntityManager的FlushModeType。

可 是我们为什么需要手工指定FlushModeType呢?默认的 flush行为听起来很有道理:如果你正在查询数据库,一定想要确保在事务中所做的任何更新都被flush到数据库。这样,查询结果才会反映这些更新。否 则,更新就可能不会体现在查询结果中;而在事务提交时,很显然,你希望对更改做flush操作。

尽 管如此,出于性能的考虑,FlushModeType.COMMIT 也是有用武之地的。数据库应用调优的最好办法就是减少不必要的数据库访问。一些Java Persistence实现可以在一次batch JDBC调用中执行所有必要的更新操作。而如果updateBeds()方法使用缺省的Flush- ModeType.AUTO模式,那么执行每次查询时都会执行相应的SQL UPDATE。而使用COMMIT,则允许entity manager在一次批处理调用中执行所有的更新操作。这会大大减少数据库访问的次数。此外,UPDATE通常会使记录处于写锁定状态(write- locked)。使用COMMIT模式时,对数据库的锁定只在JTA事务提交期间发生,从而减少了事务对数据库占用的总体时间。

锁定

Locking

EntityManager API同时支持读锁和写锁,由于锁定行为与事务的概念紧密关联,我们将在第16章详细讨论lock()方法的使用。

getDelegate()

getDelegate()

getDelegate() 方法允许你获得一个指向底层 persistence provider对象的引用,该persistence provider实现了EntityManager接口。大多数厂商都提供了针对EntityManager接口的API扩展,为了使用这些扩展功能,你 可以将获取到的delegate对象强制类型转换为厂商的私有接口。虽然从理论上讲,你应该可以编写出厂商无关的代码。但实际上,多数厂商都提供了大量针 对Java Persistence的扩展,你可以在应用程序中充分利用这些功能。而getDelegate()方法提供了一种获取并使用厂商专有API的途径。

分享到:
评论

相关推荐

    EntityManager API方法详解

    Session bean or MD bean对Entity bean的操作(包括所有的query, insert, update, delete操作)

    EntityManager,实体类数据库访问管理层

    有了实体类CUstoms,下面就可以操作实体类跟操作数据库一样的啦,我们新建一个实体类管理类 CustomsManager.cs public class CustomsManager:EntityManager { public Customs GetByName(string name) { //创建...

    java-entitymanager-generic-dao:使用 Hibernate EntityManager (Spring Boot) 的通用 Dao

    在这个实现中,我们使用 Spring Framework ORM EntityManager 使用预配置的数据源来实现基本操作,例如从数据库中插入、更新、删除和检索实体。 这种实现的主要优点是,由于这个 dao 是使用 Java 泛型实现的,我们...

    MVC3+Entity进行CURD操作

    这个是刚入门也是我这几天写的 适合新手入门

    JPA复杂查询加分页查询的快速开发

    针对使用JPA方式操作数据库的复杂查询快速开发,复制代码直接使用,快速开发

    利用Spring来管理Hibernate完整例子

    其中Hibernate每次都需要手动创建SessionFactory,Session,手动开启提交关闭事务。而这一切操作完全是由Spring来代替。使持久层更加方便,使开发人员减少持久层操作,把注意力放到业务上。

    mysql的驱动包,适合使用hibernate和jpa

    由于以前的MySQL驱动在使用hibernate的时候遇到了一些问题所以希望将这个问题告诉大家,这个驱动在使用过的时候至今没有遇到什么问题

    spring+jpa

    也是最具意义的,Spring 将 EntityManager 的创建与销毁、事务管理等代码抽取出来,并由其统一管理,开发者不需要关心这些,如前面的代码所示,业务方法中只剩下操作领域对象的代码,事务管理和 EntityManager 创建...

    JPA学习笔记-EJB-05JPA实体对象状态和实体对象的高级操作

    虽然持久化实体的状态在ORM中是一个老生常谈的问题,...在Web一般情况下也都是交给Spring去管理实体管理器(EntityManager),所以我们还是有必要啰嗦一下,至于肢体的高级操作,实际上也就是实体监听器的使用而已。

    spring-jpa-hibernate:使用Spring Data JPA和Hibernate作为JPA提供者的示例应用程序

    使用再次执行操作关系数据库 直接EntityManager访问 直接访问JPA EntityManager ,以对数据库交互进行细粒度控制 集合大小 查找映射集合的大小,而不必加载集合中的所有元素 多个EntityManager 在单个应用程序中...

    spring-boot-crud-api:支持在rest api上执行crud操作的Spring Boot应用程序

    要使用它,请执行以下操作:在DAO实现(@Repository)中,创建一个私有字段EntityManager并通过构造函数注入对其进行分配。 在服务实现,构造函数注入中,向dao实现添加一个Qualifier。 spring data jpa...

    OpenJPA 2.2.1 API (CHM格式)

    在线是指所有针对实体的操作必须在一个 EntityManager 范围中运行。这两个特征,加上 EntityManager 是非序列化的,无法在网络上传输,导致 JPA 应用无法适用于企业应用中的 C/S 实现模式。OpenJPA 扩展了这部分接口...

    EJB3.0 实例教程 -- 切片2

    6.5 持久化实体管理器ENTITYMANAGER..43 6.5.1 Entity获取find()....43 6.5.2 添加 persist().........43 6.5.3 更新 Merge() .........44 6.5.4 删除 Remove() .......44 6.5.5 执行 EJB3 QL操作createQuery() 44 ...

    Spring Data JPA/Hibernate 运行期动态模型、动态实体建表、动态字段查询的方式

    涉及到动态生成表结构,动态生成模型实体类动态查询表字段等等,经过调研发现hibernate在这方面是很方便的,调用内置API就能完成系列操作,下面贴出核心代码: /** * @author cjbi */ public class DynamicDdlTest...

    Spring3+Hibernate4+Struts2 jar包 SSH框架

    hibernate-entitymanager-4.1.6.Final.jar hibernate-envers-4.1.6.Final.jar hibernate-jpa-2.0-api-1.0.1.Final.jar javassist-3.15.0-GA.jar jboss-logging-3.1.0.GA.jar jboss-transaction-api_1.1_spec-1.0.0....

    EJB3.0 实例教程 -- 切片1

    6.5 持久化实体管理器ENTITYMANAGER..43 6.5.1 Entity获取find()....43 6.5.2 添加 persist().........43 6.5.3 更新 Merge() .........44 6.5.4 删除 Remove() .......44 6.5.5 执行 EJB3 QL操作createQuery() 44 ...

    plum-doctrine:PlumDoctrine将Doctrine整合到Plum中。 Plum是PHP的数据处理管道

    PlumDate将Doctrine整合到Plum中... 它支持具有可配置刷新间隔的批处理操作。 use Plum \ PlumDoctrine \ ORM \ EntityWriter ;$ writer = new EntityWriter ( $ entityManager );$ writer -&gt; prepare ();$ writer -&gt; w

    J2EE应用开发详解

    294 16.3.5 数据库连接池中使用JDBC 297 16.4 小结 302 第17章 ORM与Java持久化机制 303 17.1 ORM概述 303 17.2 域模型 304 17.3 实体域对象的持久化模式 304 17.4 JPA 305 17.4.1 实体 306 17.4.2 EntityManager ...

    Hibernate实战(第2版 中文高清版)

     2.2.2 使用Hibernate EntityManager   2.2.3 引入EJB组件   2.2.4 切换到Hibernate接口   2.3 反向工程遗留数据库   2.3.1 创建数据库配置   2.3.2 定制反向工程   2.3.3 生成Java源代码   2.4 与...

    Especialista-JPA:JPA专家课程资料库

    JPA专家 JPA专家课程资料库 ... 认识EntityManager 高级映射 DDL生成 级联操作 高级JPQL 标准API 本机查询 Bean验证,连接池,实体图 二级缓存 竞争与锁定 多租户 [] pg和EclipseLink []最后主题

Global site tag (gtag.js) - Google Analytics