操作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的途径。
相关推荐
在EJB(Enterprise JavaBeans)环境中,Session bean 或 MDB(Message-Driven Bean)与Entity bean交互时,EntityManager是主要的接口,它负责处理Entity bean的所有查询、插入、更新和删除操作。EntityManager实例...
而实体管理器(EntityManager)是Java Persistence API(JPA)的一部分,它提供了与Hibernate集成的关键接口,用于管理和操作数据。当我们谈论"entitymanager(hibernate)"时,意味着我们要探讨如何在Java项目中将这...
本文档为Hibernate 3.3.0.GA版本的EntityManager使用指南,主要介绍了如何在不同的环境中使用EntityManager管理持久化对象,包括实体的状态管理、查询操作、事务处理等内容。 #### 一、架构 ##### 1.1 定义 - **...
【描述】:EntityManager是Java Persistence API (JPA)中的核心组件,主要用于管理实体(Entity)对象及其在数据库中的持久化操作。这个Demo将展示如何使用EntityManager进行基本的数据操作,包括创建、查询、更新和...
Hibernate EntityManager在Hibernate Session之上提供了一层抽象,使得开发者可以使用JPA标准的API来操作数据,同时也保留了Hibernate的一些高级特性。 **2. 配置Hibernate EntityManager** 在使用Hibernate ...
4. 在事务中操作EntityManager,如保存实体、查询实体、更新实体和删除实体。 5. 使用JPQL进行复杂查询。 6. 提交或回滚事务,完成数据库操作。 **总结** OpenJPAExample项目是一个基础的OpenJPA学习示例,它展示...
- **获取和操作EntityManager**: 通过EntityManager进行CRUD操作。 - **执行查询**: 使用JPQL或Criteria API编写查询,获取数据。 6. **JPA的优势** - **简化代码**: ORM减少了手动编写SQL的需求,使得代码更...
Session bean or MD bean对Entity bean的操作(包括所有的query, insert, update, delete操作)
Hibernate EntityManager 是 Hibernate 项目的一部分,它是一个符合 JPA(Java Persistence API)规范的 ORM 解决方案,为开发者提供了一种更加面向对象的方式来处理数据库操作。在 Hibernate EntityManager 3.2 ...
【标题】"hibernate-entitymanager-3.4.0.GA" 是一个与Java持久化框架Hibernate Entity Manager相关的库,这个版本号表明它是2009年左右发布的一个稳定版本。Hibernate Entity Manager是JPA(Java Persistence API)...
【标题】"hibernate-entitymanager-4.3.4.Final.zip" 是一个与Hibernate实体管理器相关的压缩包,其中包含的是Hibernate ORM框架的一个特定版本——4.3.4.Final。Hibernate实体管理器是Java开发中用于实现Java持久化...
最后,通过EntityManager进行数据操作,享受JPA带来的标准化接口和强大的ORM功能。 综上所述,理解并熟练运用Hibernate的这三个关键组件对于任何Java开发人员来说都是至关重要的。掌握它们不仅能够提高开发效率,还...
在Spring框架中,EntityManager是Java Persistence API (JPA) 的核心接口,用于处理数据库操作。然而,有时在尝试使用Spring管理持久层时,可能会遇到一个问题:“Spring EntityManager 不能扫描jar中的class文件”...
有了实体类CUstoms,下面就可以操作实体类跟操作数据库一样的啦,我们新建一个实体类管理类 CustomsManager.cs public class CustomsManager:EntityManager { public Customs GetByName(string name) { //创建...
- **操作实体**:使用EntityManager进行增删改查操作,如persist()、merge()、remove()和find()。 - **事务处理**:在开始和结束操作之间启动和提交事务。 - **查询数据**:使用JPQL或Criteria API执行查询,并...
6. **操作实体**: 实例化实体,调用EntityManager的persist()、merge()、remove()、find()等方法完成CRUD操作。 7. **查询执行**: 使用createQuery()、createCriteria()创建查询,通过JPQL或Criteria API获取结果集...
- 实体管理器:使用EntityManager实例来操作实体,如创建(persist)、加载(find)、更新(merge)、删除(remove)等。 - JPQL查询:编写JPQL语句,执行查询并获取结果集。 - 事务处理:通过EntityManager的...
EntityManager是与数据存储进行交互的主要接口,负责对象的创建、读取、更新和删除(CRUD)操作。通过它可以管理实体的状态,执行查询,以及进行事务控制。 4. **实体(Entity)** 实体是应用程序中与数据库表...