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"という意味だと思います。便利ですね。