Extended Persistence Context の使い道 (2)
JPA仕様書の続きです。Statelessの例が5.8.1、Statefulの例が5.8.2です。赤字に注目して二つのコードの違いを探してみてください。
まずは、5.8.1の方です。こちらはTransaction-scopedなのでEnitityManagerのライフサイクルはトランザクションと同期し、トランザクション終了時にコンテナによってEnitityManagerはcloseされます。
5.8.1 Container-managed Transaction-scoped Persistence Context @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; } }
次の5.8.2の方はExtended Persistence Contextなので、そのEntityManagerのライフサイクルはStateful SessionBeanのライフサイクルと同期し、Stateful SessionBeanがremoveされるまでEntityはDetached状態になりません。
5.8.2 Container-managed Extended Persistence Context @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; } }
5.8.1の例ではcreateLineItemの中でem.persist(li);を実行しているのに対し、5.8.2ではそれに対応する文は存在しないことに気づきましたか?
5.8.1のStateless SessionBeanではメソッドアクセス毎にEntityはDetached状態になるので、createLineItemの引数であるorderもDetached状態になります。したがって、orderをManaged状態にするためにはem.persistを明示的に実行することが必要になります。
一方で、5.8.2のStateful SessionBeanではorderはすでにManaged状態なので、それにitemを追加するとEntityManagerによって自動的にitemもManagedになります。
Stateful SessionBeanでExtended Persistence Contextを使って更新系のプログラムを書くなら、最初にEntityをロードした後は、そのEntityのDetachedやManagedの違いをあることをあまり意識する必要はありません。これがStateful SessionBeanとExtended Persistence Contextの組合せが"natural cache"という意味だと思います。便利ですね。