应用程序管理的实体管理器 | 容器管理的实体管理器 |
使用实体管理器工厂指定来获取实体管理器实例 | 使用 @PersistenceContext 标注或 JNDI 查找指定来获取实体管理器实例 |
必须使用扩展范围的持久性上下文 | 必须使用事务范围的持久性上下文 |
必须使用应用程序管理的事务 | 必须使用应用程序管理的事务 |
@PersistenceUnit(unitName="CatalogPu") EntityManagerFactory emf
。然后,代码应保留该工厂以进行重用,直至使用完其实体管理器时为止。实体管理器工厂是线程安全的,可以将其保留在应用程序范围内;因此,建议使用应用程序管理的实体管理器的仅限 Web 应用程序将该工厂缓存在应用程序范围内,并在请求之间共享它。请注意,如果应用程序关闭某个实体管理器工厂,则认为它的所有实体管理器均处于关闭状态。 EntityManager em = emf.createEntityManager()
调用)来指定的。可随后使用实体管理器 API 永久保留或查询实体。 @PersistenceUnit private EntityManagerFactory emf;//declared as instance variable for re-use.
...
//this method uses entity manager to persist an entity Item.java
public void addItem(Item item){
EntityManager em = emf.createEntityManager();
try{
...
em.persist(item);
...
} finally {
em.close();
}
close
、isOpen
和 joinTransaction
方法来管理实体管理器及其生命周期。应用程序在使用完实体管理器时,需要将其关闭。实体管理器不是线程安全的,因此不应以非线程安全的方式保留对实体管理器实例的引用。由于应用程序管理的实体管理器具有扩展范围的持久性上下文,因此,代码可以选择将实体管理器保持打开状态(针对几个请求),并在完成时将其关闭。应用程序管理的实体管理器还可以模拟事务范围的实体管理器的行为,并在创建实体管理器的同一方法结束时将其关闭。这样,扩展范围的持久性上下文可提供更大的灵活性,因为它们可以实现事务范围的持久性上下文的行为并且跨多个 HTTP 请求和多个事务。一种将实体管理器保持打开状态并使用扩展范围的持久性上下文的使用情况是:多页面表单可能使用几个表单提交来收集实体中的所有用户信息;在收集了所有信息后刷新所有实体并将其提交到数据库。 javax.persistence.EntityManager
接口中的某些方法要求必须在事务上下文中调用它们。如果没有事务以及持久性上下文在事务范围内,这些方法将抛出 TransactionRequiredException
。这些方法对数据库中的数据执行写入或更新操作。开发者应该确保在调用这些方法之前具有事务上下文。这些方法是 persist
、merge
、remove
、flush
和 refresh
方法。JTA 实体管理器代码 | 资源本地实体管理器代码 |
@PersistenceUnit EntityManagerFactory emf; |
@PersistenceUnit
private
EntityManagerFactory emf; ... |
不正确的做法:非线程安全,因而这种方法不可取 |
正确的做法:线程安全。 在开头使用标注来声明 JNDI 依赖关系;使用 JNDI 查找来获取实体管理器。 |
public class MyServlet extends HttpServelet {
@PersistenceContext
EntityManager em; public void doGet( HttpServletRequest req,
... the same
//entity manager instance em.persist(item) ....some code
using the entity manager } |
entity manager so this method-scoped em is thread safe. also notice JNDI lookup to get em ....some code
using the entity manager } |
@PersistenceContext(name="foo",
unitName="myPuName")
public class MyServlet extends HttpServelet {
@Resource UserTransaction utx;
public void doGet(HttpServletRequest req,
HttpServletResponse resp) throws throws
ServletException, IOException {
EntityManager em = (EntityManager) ic.lookup("java:comp/env/foo");
//get data from request
String name = request.getParameter("item_name");
...
//create new Item entity
Item item = new Item();
//set values of Item entity
item.setName(name);
...
utx.begin();
em.persist(item); //persist and add new Item to database
utx.commit();
...
}
@Resource
标注注入了一个用于控制 JTA 事务的 UserTransaction 实例。UserTransaction 是线程安全的,因此,可以将其保存为由其他请求共享的实例变量。由于我们此处执行的是数据库写入操作,因此,我们仅在调用 em.persist()
之前启动事务并随后进行提交。容器管理实体管理器实例的生命周期,并在方法结束时将其关闭。请注意,Servlet 类具有标注 @PersistenceContext(name="foo", unitName="myPuName")
,它用于声明对持久性上下文的依赖关系,然后在 Servlet.doGet 方法中使用 JNDI 查找并获取实体管理器(通过 EntityManager em = ic.lookup("java:comp/env/foo")
)。