EJB3持久化规范(第五章)

来源:互联网 发布:php pdo 教程 编辑:程序博客网 时间:2024/05/16 00:25
1         实体管理器和持久化上下文
1.1    持久化上下文
持久化上下文是一个受管理实体实例的集合,在持久化上下文中的每一个实体实例有一个唯一的标识。在持久化上下文中,实体实例及其生命周期都由实体管理器管理。
在java EE环境中,通常会在多个组件中使用一个JTA事务。这些组件经常需要在一个事务内获取同一个持久化上下文。为了在Java EE环境中满足实体管理器的这种用法,当一个实体管理器被注入到一个组件或直接通过JNDI搜索到管理器时,它的持久化上下文会自动的随着当前JTA事务一起传播,并且引用同一个持久化单元的EntityManager将提供获取当前JTA事务中的同一个持久化上下文。由Java EE容器进行的持久化上下文的传播避免了应用在组件间传递EntityManager实例。容器用这种方式管理持久化上下文的实体管理器称为容器管理的实体管理器。容器管理的实体管理器的生命周期由Java EE容器管理。
在Java EE环境中,很少有应用需要获取“独立的”持久化上下文——也就是说,不随着JTA事务而穿越多个EntityManager引用。而是,每创建一个实体管理器实例都会创建一个鼓励的持久化上下文,这个持久化上下文不能通过在同一个事务内的其他实体管理器获得。这种使用方式可以通过EntityManagerFactory的createEntityManager方法来实现。这种由应用创建和销毁持久化上下文的实体管理器称为应用管理的实体管理器。应用管理的实体管理器的生命周期由应用自己来管理。
要求在Java EE的web 容器和EJB容器内都要支持容器管理的实体管理器和应用管理的实体管理器以及它们的持久化上下文。在EJB环境中,通常使用容器管理的实体管理器。
在java SE环境和Java EE应用客户端容器中,只要求支持应用管理的实体管理器。(注:注意不要求在应用客户端容器中支持JTA
1.2    获取EntityManager
从实体管理器工厂中获取指向一个持久化上下文的实体管理器。
当使用容器管理的实体管理器(在Java EE环境中)时,应用不和实体管理器工厂交互。实体管理器直接通过依赖注入或JNDI获得,容器负责与实体管理器工厂交互。
当使用应用管理的实体管理器时,应用必须使用实体管理器工厂来管理实体管理器和持久化上下文的生命周期。
实体管理器可以不被多个线程间共享。实体管理器可以只在单线程方式下被获得。
1.2.1    在Java EE环境中获取EntityManager
可以通过依赖注入或JNDI查找来获得容器管理的EntityManager。容器管理持久化上下文的生命周期,以及透明的创建和管理实体管理器实例。
可以用PersitenceContext注释来注入EntityManager。Type元素指明是否使用事务范围的还是扩展的持久化上下文,这在4.6章节中有述。可选的unitName用于指派一个持久化单元(参看7.4.2章节)。
例如:
@PersistenceContext
EntityManager em;
@PersistenceContext(type=PersistenceContextType.EXTENDED)
EntityManager orderEM;
下面是使用JNDI查找的方式获取一个实体管理器:
@Stateless
@PersistenceContext(name="OrderEM")
public class MySessionBean implements MyInterface {
@Resource SessionContext ctx;
public void doSomething() {
EntityManager em = (EntityManager)ctx.lookup("OrderEM");
...
}
}
1.2.2    获取应用管理的EntityManager
应用可以通过实体管理器工厂来获得EntityManager。
用于获取一个应用管理的实体管理器的EntityManagerFactory API与是否是用于Java EE还是Java SE环境无关。
1.3    获取实体管理器工厂
EntityManagerFactory接口供应用来创建应用管理的实体管理器。(注:也用于Java EE容器内部。参见4.9章节)
每个实体管理器工厂提供相同配置的实体管理器实例(例如,配置为连接到同一个数据库,使用由应用实现定义的相同的初始化设置,等等)。
在JVM中可以同时获取多个实体管理器工厂实例。(注:这可能是在使用多个数据库的情况下,因为在通常的配置中一个单一的实体管理器只和一个数据库通信。但是,每个持久化单元只有一个实体管理器工厂。)
EntityManagerFactory的方法都是线程安全的。
1.3.1    在Java EE容器内获取实体管理器工厂
在J2EE容器内,EntityManagerFactory可以用PersistenceUnit注释注入或者通过JNDI查找。可选的unitName元素用于指明使用哪个持久化单元(参见7.4.2章节)。
例如:
@PersistenceUnit
EntityManagerFactory emf;
1.3.2    在Java SE环境下获取实体管理器工厂
在Java EE容器环境外,javax.persistence.Persistence类是提供获取实体管理器工厂的入口。应用通过调用这个类的createEntityManagerFactory方法创建实体管理器工厂,在6.2.1章节中进行描述。
例如:
EntityManagerFactory emf =
javax.persistence.Persistence.createEntityManagerFactory("Order");
EntityManager em = emf.createEntityManager();
1.4    EntityManagerFactory接口
EntityManagerFactory接口用于应用获取应用管理的实体管理器。当应用使用完实体管理器,并且/或者在应用关闭时,应用应当关闭实体管理器工厂。一旦EntityManagerFactory被关闭,它的所有实体管理器都被认为是关闭的。
public interface javax.persistence.EntityManagerFactory {
/**
 * Create a new EntityManager.
 * This method returns a new EntityManager instance each time
 * it is invoked.
 * The isOpen method will return true on the returned instance.
 */
public EntityManager createEntityManager();
/**
 * Create a new EntityManager with the specified Map of
 * properties.
 * This method returns a new EntityManager instance each time
 * it is invoked.
 * The isOpen method will return true on the returned instance.
 */
public EntityManager createEntityManager(Map map);
/**
 * Close the factory, releasing any resources that it holds.
 * After a factory instance is closed, all methods invoked on
 * it will throw an IllegalStateException, except for isOpen,
 * which will return false. Once an EntityManagerFactory has
 * been closed, all its entity managers are considered to be
 * in the closed state.
 */
public void close();
/**
 * Indicates whether the factory is open. Returns true
 * until the factory has been closed.
 */
public boolean isOpen();
}
传入createEntityManager方法的Properties可以包含任何提供商特有的属性,提供商必须忽略不能被识别的属性。
提供商应当为这些属性使用自己的命名空间(例如,com.acme.persistence.logging),不应当那些使用javax.persistence和它的子空间。Javax.persistence是本规范的保留空间。
1.5    控制事务
根据实体管理的事务类型,EntityManager操作涉及的事务可以通过JTA或通过使用本地资源的EntityTransaction API来控制,它被映射成一个资源上的资源事务,这些资源成为实体管理器管理实体的基础。
由JTA管理事务的实体管理器称为JTA实体管理器。
由应用通过EntityTransaction API管理事务的实体管理器称为本地资源实体管理器。
容器管理的实体管理器一定是JTA实体管理器。JTA实体管理器只用于Java EE容器。
应用管理的实体管理器可以是JTA实体管理器,也可以是本地资源实体管理器。
实体管理器用给定的事务类型来定义——或者是JTA或者是本地资源——同时,它的实体管理器工厂会在后台被配置和创建。参见5.2.1.2和6.1.1章节。
在Java EE web容器和EJB容器内要求支持JTA实体管理器和本地资源实体管理器。在EJB环境中,通常使用JTA实体管理器。通常情况下,在Java SE环境下只支持本地资源的实体管理器。
1.5.1    JTA EntityManager
通过JTA控制事务的实体管理器称为JTA实体管理器。JTA实体管理器参与当前的JTA事务,它在实体管理器的外部开始和提交,并且广播到后台的资源管理器。
1.5.2    本地资源EntityManager
实体管理器的事务是由应用通过EntityTransaction API控制的实体管理器称为本地资源的实体管理器。本地资源实体管理器事务通过持久化提供商被映射到资源事务。本地资源实体管理器可以使用服务器资源或本地资源来连接数据库,且不关心JTA事务的持久化,不管它是否是活动的。
1.5.2.1         EntityTransaction接口
EntityTransaction接口用于控制在本地资源实体管理器上的资源事务。EntityManager.getTransaction方法返回EntityTransaction接口。
当使用本地资源实体管理器且持久化提供商运行时抛出引起事务回滚的异常时,持久化提供上必须标记事务回滚。
如果EnityTransaction.commit操作失败,持久化提供商必须回滚事务。
public interface EntityTransaction {
/**
 * Start a resource transaction.
 * @throws IllegalStateException if isActive() is true.
 */
public void begin();
/**
 * Commit the current transaction, writing any unflushed
 * changes to the database.
 * @throws IllegalStateException if isActive() is false.
 * @throws RollbackException if the commit fails.
 */
public void commit();
/**
 * Roll back the current transaction.
 * @throws IllegalStateException if isActive() is false.
 * @throws PersistenceException if an unexpected error
 *condition is encountered.
 */
public void rollback();
/**
 * Mark the current transaction so that the only possible
 * outcome of the transaction is for the transaction to be
 * rolled back.
 * @throws IllegalStateException if isActive() is false.
 */
public void setRollbackOnly();
/**
 * Determine whether the current transaction has been marked
 * for rollback.
 * @throws IllegalStateException if isActive() is false.
 */
public boolean getRollbackOnly();
/**
 * Indicate whether a transaction is in progress.
 * @throws PersistenceException if an unexpected error
 *condition is encountered.
 */
public boolean isActive();
}
1.5.3    例子
下面的例子解释在Java SE环境下创建实体管理器工厂,以及用它来创建和使用一个本地资源的实体管理器。
import javax.persistence.*;
public class PasswordChanger {
public static void main (String[] args) {
EntityManagerFactory emf =
Persistence.createEntityManagerFactory("Order");
EntityManager em = emf.createEntityManager();
em.getTransaction().begin();
User user = (User)em.createQuery
            ("SELECT u FROM User u WHERE u.name=:name AND
u.pass=:pass")
            .setParameter("name", args[0])
            .setParameter("pass", args[1])
            .getSingleResult();
if (user!=null)
user.setPassword(args[2]);
em.getTransaction().commit();
em.close();
emf.close ();
    }
}
1.6    容器管理的持久化上下文
当使用容器管理的持久化上下文时,持久化上下文的生命周期被自动地管理,且对应用是透明的,同时持久化上下文随着JTA事务传播。
容器管理的持久化上下文可以定义为单事务的生命期,也可以定义为跨多个事务的生命期,这在持久化上下文所在的EntityManager被创建时由PersistenceContextType来指定。本规范分别称这种持久化上下文为事务范围的持久化上下文和扩展的持久化上下文。
持久化上下文的生命期由PersistenceContext注释符或在XML中用persistence-context-ref元素。缺省情况下使用事务范围的持久化上下文。
第4.6.1和4.6.2章节描述了事务范围和扩展的持久化上下文但是没有描述持久化上下文的传播。持久化上下文的传播在第4.6.3章节中描述。
持久化上下文总是和一个实体管理器工厂相关联。在以后章节中只要提到“持久化上下文”,就应该理解为“关联了一个实体管理器工厂的持久化上下文”。
1.6.1    容器管理的事务范围的持久化上下文
应用可以通过注入或在JNDI命名空间中lookup的方式获得一个带有事务范围的持久化上下文的实体管理器,这个持久化上下文绑定到JTA事务上。这个持久化上下文的类型缺省定义为PersistenceContextType.TRANSACTION。
当在活动的JTA事务中调用容器管理的实体管理器时(注:特指当EntityManager接口的方法被调用时),开始一个新的持久化上下文,但这个持久化上下文还没有和JTA事务建立关联。在持久化上下文被创建后才和JTA事务建立关联。
当关联的JTA事务提交或回滚时,持久化上下文结束,并且由EntityManager管理的所有实体变成脱管的。
如果在事务范围外部调用EntityManager,那么在方法调用的最后,所有从数据库加载的实体将立刻变成托管的。
1.6.2    容器管理的扩展持久化上下文
容器管理的扩展持久化上下文只能在有状态的会话bean中被初始化。它从被声明为依赖于一个类型为PeristenceContextType.EXTEND的实体管理器的有状态会话bean被创建开始存在,称为绑定到有状态会话bean。通过PersistenceContext注释符或在XML中的persistence-context-ref元素来声明使用容器管理的扩展持久化上下文。
持久化上下文在有状态的会话bean的@Remote方法完成后被容器关闭(或者在有状态会话bean被销毁后被关闭)。
1.6.2.1         扩展持久化上下文的继承
如果一个有状态会话bean实例化一个有扩展持久化上下文的有状态会话bean、,那么第一个有状态会话bean的扩展持久化上下文被第二个有状态会话bean继承并且绑定到它上,且这个规则迭代执行下去——不管这些有状态会话bean在创建时事务是否活动。
如果持久化上下文有状态会话bean继承,那么容器在所有继承它的有状态会话bean被删除或被销毁后才关闭该持久化上下文。
1.6.3    持久化上下文的传播
正如在4.1章节中所述,一个持久化上下文可以对应一到多个JTA实体管理器实例(它们都和同一个实体管理器关联——注:从不同的实体管理器工厂获得的实体管理器从不共享同一个持久化上下文)。
同JTA事务的传播一样,持久化上下文也在多个实体管理器实例间传播。
持久化上下文的传播只应用在本地环境中,不能进行远程传播。
1.6.3.1         持久化上下文传播的要求
被容器跨越多个组件调用传播的持久化上下文要求如下。
1.        如果调用一个组件但没有JTA事务或JTA事务不传播,那么持久化上下文不传播。
如果随后在组件内调用一个实体管理器,那么:
调用定义为PersistenceContextType.TRANSACTION的实体管理器会引起产生一个新的持久化上下文(正如在4.6.1章节中所述)。
调用定义为PersistenceContextType.EXTEND的实体管理器会引起已存在的扩展持久化上下文绑定到该组件上。
如果在JTA事务内调用实体管理器,那么持久化上下文将被绑定到JTA事务上。
2.        如果调用一个组件,且JTA事务被广播到该组件,那么:
如果该组件是绑定了扩展持久化上下文的有状态会话bean,并且在JTA事务上绑定了一个不同的持久化上下文,那么容器抛出EJBException。
否则,如果在JTA事务上绑定一个持久化上下文,那么传播并使用该持久化上下文。
1.6.4    例子
1.6.4.1         容器管理的事务范围的持久化上下文
@Stateless
public class ShoppingCartImpl implements ShoppingCart {
@PersistenceContext EntityManager em;
public Order getOrder(Long id) {
return em.find(Order.class, id);
}
public Product getProduct(String name) {
return (Product) em.createQuery("select p from Product p
where p.name = :name")
.setParameter("name", name)
.getSingleResult();
}
 public LineItem createLineItem(Order order, Product product, int
quantity) {
LineItem li = new LineItem(order, product, quantity);
order.getLineItems().add(li);
em.persist(li);
return li;
}
}
1.6.4.2         容器管理的扩展持久化上下文
@Stateful
@Transaction(REQUIRES_NEW)
public class ShoppingCartImpl implements ShoppingCart {
@PersistenceContext(type=EXTENDED)
EntityManager em;
private Order order;
private Product product;
public void initOrder(Long id) {
order = em.find(Order.class, id);
}
public void initProduct(String name) {
product = (Product) em.createQuery("select p from Product p
where p.name = :name")
.setParameter("name", name)
.getSingleResult();
}
public LineItem createLineItem(int quantity) {
LineItem li = new LineItem(order, product, quantity);
order.getLineItems().add(li);
return li;
}
}
1.7    应用管理的持久化上下文
当使用管理的久化上下文时,应用直接通过持久化提供商提供的实体管理器工厂进行交互来管理实体管理器的生命周期以及获得和销毁持久化上下文。
所有这些应用管理的持久化上下文在范围上是被扩展的,以及是跨越多个事务的。
EntityManager.close()和isOpen方法用于管理应用管理的实体管理器和它关联的持久化上下文的生命周期。
EntityManager.close()方法用于关闭一个操作一个实体管理器并是否它关联的持久化上下文和其他资源。在close方法被调用后,应用不能调用EntityManager实例上的任何方法,除了getTransaction和isOpen,否则抛出IllegalStateException。如果在事务活动时调用close方法,那么持久化上下文仍然被管理直到事务完成。
EntityManager.isOpen方法表示实体管理器是否是open的。isOpen方法在实体管理器被关闭前一直返回true。
扩展的持久化上下文从使用EntityManagerFactory.createEntityManager创建实体管理器开始存在,直到通过EntityManager.close关闭实体管理器。从应用管理的实体管理器获得的扩展持久化上下文是独立的——不随着事务传播。
当使用JTA应用管理的实体管理器时,如果在JTA事务外创建实体管理器,那么应用负责调用EntityManager.joinTransaction来建立实体管理器与事务的的关联(如果希望建立关联)。
1.7.1    例子
1.7.1.1         在无状态会话bean中使用应用管理的持久化上下文
/*
 * Container-managed transaction demarcation is used.
 * Session bean creates and closes an entity manager in
 * each business method.
 */
@Stateless
public class ShoppingCartImpl implements ShoppingCart {
@PersistenceUnit
private EntityManagerFactory emf;
public Order getOrder(Long id) {
EntityManager em = emf.createEntityManager();
Order order = (Order)em.find(Order.class, id);
em.close();
return order;
}
public Product getProduct() {
EntityManager em = emf.createEntityManager();
Product product = (Product) em.createQuery("select p from
Product p where p.name = :name")
.setParameter("name", name)
.getSingleResult();
em.close();
return product;
}
publicLineItemcreateLineItem(Orderorder,Productproduct,int
quantity) {
EntityManager em = emf.createEntityManager();
LineItem li = new LineItem(order, product, quantity);
order.getLineItems().add(li);
em.persist(li);
em.close();
return li; // remains managed until JTA transaction ends
}
}
1.7.1.2         在无状态会话bean中使用应用管理的持久化上下文
/*
 * Container-managed transaction demarcation is used.
 * Session bean creates entity manager in PostConstruct
 * method and clears persistence context at the end of each
 * business method.
 */
@Stateless
public class ShoppingCartImpl implements ShoppingCart {
@PersistenceUnit
private EntityManagerFactory emf;
private EntityManager em;
@PostConstruct
public void init()
em = emf.createEntityManager();
}
public Order getOrder(Long id) {
Order order = (Order)em.find(Order.class, id);
em.clear(); // entities are detached
return order;
}
public Product getProduct() {
Product product = (Product) em.createQuery("select p from
Product p where p.name = :name")
.setParameter("name", name)
.getSingleResult();
em.clear();
return product;
}
publicLineItemcreateLineItem(Orderorder,Productproduct,int
quantity) {
em.joinTransaction();
LineItem li = new LineItem(order, product, quantity);
order.getLineItems().add(li);
em.persist(li);
// persistence context is flushed to database;
// all updates will be committed to database on tx commit
em.flush();
// entities in persistence context are detached
em.clear();
return li;
}
@PreDestroy
public void destroy()
em.close();
}
}
1.7.1.3         在有状态会话bean中使用应用管理的持久化上下文
//Container-managed transaction demarcation is used
@Stateful
public class ShoppingCartImpl implements ShoppingCart {
@PersistenceUnit
private EntityManagerFactory emf;
private EntityManager em;
private Order order;
private Product product;
@PostConstruct
public void init() {
em = emf.createEntityManager();
}
public void initOrder(Long id) {
order = em.find(Order.class, id);
}
public void initProduct(String name) {
product = (Product) em.createQuery("select p from Product p
where p.name = :name")
.setParameter("name", name)
.getSingleResult();
}
public LineItem createLineItem(int quantity) {
em.joinTransaction();
LineItem li = new LineItem(order, product, quantity);
order.getLineItems().add(li);
return li;
}
@Remove
public void destroy() {
em.close();
}
}
1.7.1.4         带有资源事务的应用管理的持久化上下文
// Usage in an ordinary Java class
public class ShoppingImpl {
private EntityManager em;
private EntityManagerFactory emf;
public ShoppingCart() {
emf = Persistence.createEntityManagerFactory("orderMgt");
em = emf.createEntityManager();
}
private Order order;
private Product product;
public void initOrder(Long id) {
order = em.find(Order.class, id);
}
public void initProduct(String name) {
product = (Product) em.createQuery("select p from Product p
where p.name = :name")
.setParameter("name", name)
.getSingleResult();
}
public LineItem createLineItem(int quantity) {
em.getTransaction().begin();
LineItem li = new LineItem(order, product, quantity);
order.getLineItems().add(li);
em.getTransaction().commit();
return li;
}
public void destroy() {
em.close();
emf.close();
}
}
1.8    对容器的要求
1.8.1    应用管理的持久化上下文
当使用应用管理的持久化上下文时,容器必须初始化实体管理器工厂并通过JNDI把它暴露给应用。容器可以使用内部的API取创建实体管理器工厂,也可以用PersistenceProvider.createContainerEntityManagerFactory来创建。但是要求容器支持第三方的持久化提供商,因此在这种情况下容器必须使用PersistenceProvider.createContainerEntityManagerFactory来创建实体管理器工厂,以及在关闭系统前使用EntityManager.close方法来销毁实体管理器工厂(如果在应用关闭前没有关闭它)。
1.8.2    容器管理的持久化上下文
容器负责管理容器管理的持久化上下文的生命周期,负责为web组件、会话bean和消息驱动bean注入EntityManager,以及负责让使用者可以通过JNDI获取到EntityManager引用。
当容器使用第三方持久化提供商进行操作时,它使用在4.9章节中定义的协议来创建和销毁容器管理的持久化上下文。没有规定对每一个持久化上下文是否要创建一个新的实体管理器实例,或是否在某些时可以重用实体管理器。也没有规定容器如何维护持久化上下文和JTA事务直接的关系。
如果一个持久化上下文已经和一个JTA事务关联,那么容器在事务范围内为接下来的调用使用这个持久化上下文,使用规则遵循在4.6.3章节中定义的持久化上下文传播规则。
1.9    容器和持久化提供商之间的运行时协议
本章描述容器和持久化提供商之间的运行时协议。要求容器支持这些协议(当不使用第三方的持久化时不要求容器支持这些协议:容器可以使用这些API或使用自己的API)。
1.9.1    容器的职责
如果EntityManager没有和JTA事务关联,则负责管理事务范围的持久化上下文。
当在JTA事务中的业务方法第一次调用设置为PersistenceContextType.TANSACTION的实体管理器时,容器通过调用EntityManagerFactory.createEntityManager来创建一个实体管理器实例。
在JTA事务完成后(提交或回滚),容器通过调用EntityManager.close方法来关闭实体管理器(注:容器可以用池来存储EntityManager而不是每次都创建然后关闭,从池中获取一个EntityManager然后调用它的clear方法)。
如果使用事务范围的持久化上下文且EntityManger的persist、remove、merge或refresh方法在没有活动事务的情况下被调用,则容器必须抛出TransactionRequireException。
对设置为扩展持久化上下文的有状态会话bean来说:
当一个声明为依赖一个设置为PersistenceContextType.EXTENDED的实体管理器的有状态会话bean被创建时,容器调用EntityManagerFactory.createEntityManager方法创建一个实体管理器。
在有状态会话bean和其他所有继承同一个持久化上下文的有状态会话bean被清除后,容器通过调用EntityManager.close方法来关闭实体管理器。
当调用有状态会话bean的业务方法时,如果有状态会话bean使用容器管理的事务分割,并且实体管理器还没有和当前事务关联,那么容器将实体管理器和当前JTA事务关联起来并调用EntityManager.joinTransaction方法。如果和JTA事务关联的持久化上下文不同,那么容器抛出EJBException。
当调用有状态会话bean的业务方法时,如果有状态会话bean使用受管理的事务分割,并且在这个方法内开始一个UserTransaction,那么容器将JTA事务和持久化上下文关联起来并调用EntityManager.joinTransaction。
如果应用调用容器管理的实体管理器的EntityManager.close方法,那么容器必须抛出IllegalStateException。
当容器创建实体管理器时,它可以通过使用EntityManagerFactory.createEntityManager(Map map)方法传入一个属性map。如果已经在PersistenceContext注释中指定了属性或者在persistence-context-ref元素中指定了属性,那么必须使用这个方法并且在map中必须包含那些已指定的属性。
1.9.2    提供商的责任
提供商不知道事务范围的和扩展的持久化上下文之间的区别。它为容器提供实体管理器,并且为事务注册同步通知。
当调用EntityManagerFactory.createEntityManager时,提供商必须创建并返回一个新的实体管理器。如果有活动的JTA事务,那么提供商必须基于JTA事务注册同步通知。
当调用EntityManager.joinTransaction时,如果前一个joinTransaction调用还没有被处理,那么提供商必须基于当前JTA事务注册同步通知。
当JTA事务提交时,提供商必须flush所有更改的实体状态到数据库中。
当JTA事务回滚时,提供商必须脱管所有被管理的实体。
当提供上抛出引起事务回滚的异常时,提供商必须将事务标记为回滚。
当调用EntityManager.close时,提供商应当释放所有的资源,这些资源可以在所有涉及实体管理器的过期的事务完成后被收集。如果实体管理器已经是关闭状态,提供商必须抛出IllegalStateException。
当调用EntityManager.clear时,提供商必须脱管所有被管理的实体。