日期:2014-05-19  浏览次数:20679 次

The Java EE 6 Tutorial 第32章 JPA简介 (三) 管理实体
管理实体

实体由实体管理器(entity manager)管理,即javax.persistence.EntityManager实例。每个EntityManager实例都和一个持久化上下文关联:存在于特定数据存储的一套受管的实体实例。一个持久化上下文定义实体的作用域,实体在此作用域下创建、持久、删除。EntityManager接口定义了用来和持久化上下文交互的方法。



EntityManager接口

EntityManager API可创建、删除持久化实体实例,通过实体主键查找实体,也可以在实体上执行查询。


容器管理的实体管理器

对于容器托管的实体管理器(container-managed entity manager),管理器实例的持久化上下文会由容器自动传播(propagate),范围是使用了带JTA事务的实体管理器的应用组件。
With a an EntityManager instance’s persistence context is automatically propagated by the container to all application components that use the EntityManager instance within a single Java Transaction API (JTA) transaction.

JTA事务通常跨应用组件调用。要完成JTA事务,这些组件通常需要访问同一个持久化上下文。通过将实体管理器(EntityManager)注入到应用组件来实现,只要使用javax.persistence.PersistenceContext注解即可。持久化上下文会同JTA事务一起被自动传播,指向同一个持久化单元的实体管理器引用都可以在事务内访问持久化上下文。通过自动传播持久化上下文,应用组件不需要为了保证单一事务而来回传递EntityManager实例的引用。Java EE容器会管理容器托管实体管理器的生命周期。

要获得EntityManager实例,只需要将实体管理器注入应用组件:

@PersistenceContext
EntityManager  em;



应用管理的实体管理器
对于应用管理的实体管理器(application-managed entity manager),不同的是,持久化上下文吗不会传播到应用组件。EntityManager实例的生命周期也是由应用控制。

应用管理的实体管理器适用于:应用程序需要访问的持久化上下文不与横跨多个EntityManager实体的JTA事务绑定。 (Application-managed entity managers are used when applications need to access a persistence context that is not propagated with the JTA transaction across EntityManager instances in a particular persistence unit.)这种情况下,每个EntityManager创建一个新的独立的持久化上下文。EntityManager及其关联的持久化上下文由应用程序显式的创建。因EntityManager非线程安全而不能直接注入EntityManager实例时,也使用应用管理的实体管理器。EntityManagerFactory实例是线程安全的。

这种情况下,应用使用javax.persistence.EntityManagerFactory的createEntityManager方法,创建EntityManager实例。

要获取EntityManager实例,你必须先取得EntityManagerFactory实例。可以使用javax.persistence.PersistenceUnit注解,将EntityManagerFactory实例注入应用组件:

@PersistenceUnit
EntityManagerFactory  emf;

从EntityManagerFactory实例取得EntityManager实例:

EntityManager  em  = emf.createEntityManager();

应用管理的实体管理器不会自动传播JTA事务上下文,这种应用需要手动获取JTA事务管理器,并在执行实体操作时,添加事务分界(demarcation)信息。javax.transaction.UserTransaction接口定义了以下方法:开始事务(begin)、提交事务(commit)、回滚事务(roll back)。可以使用@Resource注解将UserTransaction注入到带有一个实例变量中:

@Resource
UserTransaction utx;

可以调用UserTransaction.begin方法来开始一个事务。当所有实体操作完成后,调用UserTransaction.commit方法来提交一个事务。UserTransaction.rollback方法可用来回滚当前事务。

下面的例子演示了如何在应用中使用应用管理的实体管理器来管理事务:

@PersistenceContext EntityManagerFactory  emf; EntityManager  em;


@Resource
UserTransaction utx;
...
em  = emf.createEntityManager();
try {
utx.begin();
em.persist(SomeEntity);
em.merge(AnotherEntity);
em.remove(ThirdEntity);
utx.commit();
} catch   (Exception e)  {
utx.rollback();
}

用EntityManager查找实体
EntityManager.find方法可根据实体的主键,在数据存储中查找实体:

@PersistenceContext
EntityManager  em;
public void  enterOrder(int custID, Order  newOrder) {
Customer cust = em.find(Customer.class, custID);
cust.getOrders().add(newOrder);
newOrder.setCustomer(cust);
}

管理实体实例的生命周期
你能使用EntityManager实例调用实体上的操作,来管理实体实例。实体实例可以处于四种状态之一:new(新建), managed(受控), detached(分离), removed(删除)。

■ 新建实体实例没有持久化标识,而且也没有和任何持久化上下文关联。
■ 受控实体实例有持久化标识,并且和持久化上下文关联。
■ 分离实体实例有持久化标识,但是当前没有和持久化上下文关联。
■ 删除的实体有持久化标识,也和持久化上下文关联,但是计划将从数据存储中删除。


持久化实体实例
新建实体实例可以通过调用persist方法来变为受控状态并持久,另外由其他实体persist操作引起的级联调用也可以,只要其他实体在关系注解中将cascade元素设置为PERSIST或者ALL。这意味着当persist操作关联的事务完成后,实体的数据会保存到数据库。如果实体已经是受控状态,则persist操作会被忽略,但是persist操作会级联到关联的实体,即



关系注解中,cascade元素被设为PERSIST或ALL的实体。如果persist操作调用在删除实体实例上,那实体就会变为受控状态。如果实体是分离状态,则可能persist抛出IllegalArgumentExceptio