若 您以Java EE容器來管理JPA相關資源,則您可以使用資源注入的方式取得EntityManager,並可由容器來為您管理Persistence Context,每個EntityManager會關聯至一個Persistence Context,容器會管理Persistence Context的存活範圍,像是Transaction-scoped或Extended-scoped,Persistence Context管理一組Entity,這些進階議題之後介紹。
以下的例子使用Session Facade模式,在一個Stateful Session Bean注入EntityManager,Servlet客戶端利用Session Bean來進行操作,首先定義Stateful Session Bean:
- EntitySessionRemote.java
package onlyfun.caterpillar;
import javax.ejb.Remote;
@Remote
public interface EntitySessionRemote {
    public void save(User user);
    public User findById(Long id);
    public void clearup();
}- EntitySessionBean.java
package onlyfun.caterpillar;
import javax.ejb.*;
import javax.persistence.*;
@Stateful
public class EntitySessionBean implements EntitySessionRemote {
    @PersistenceContext(unitName="sample")
    private EntityManager entityManager;
    
    public void save(User user) {
        entityManager.persist(user);
    }
    public User findById(Long id) {
        User user = entityManager.find(User.class, id);
        return user;
    }
    @Remove
    public void clearup() {
    }
}在這邊使用@PersistenceContext注入EntityManager實例,這樣的方式取得的EntityManager,稱之 為Container-Managed EntityManager,其中unitName屬性指定了persistence.xml中的Persistence Context名稱,Persistence Context預設為Transaction-scoped,也就是在方法開始前會啟始交易,結束後停止交易,Persistence Context的存活範圍在交易之間。
注意到,EntityManager不是Thread-safe,所以要注意在多執行緒下共用存取的同步問題,在這邊使用Stateful Session Bean,讓每個客戶端取得一個Session Bean實例,並獨自使用一個EntityManager。
在persistence.xml的部份:
- persistence.xml
<?xml version="1.0" encoding="UTF-8"?>
<persistence version="1.0" xmlns="http://java.sun.com/xml/ns/persistence" 
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
xsi:schemaLocation="http://java.sun.com/xml/ns/persistence 
http://java.sun.com/xml/ns/persistence/persistence_1_0.xsd">
  <persistence-unit name="sample" transaction-type="JTA">
    <jta-data-source>jdbc/sample</jta-data-source>
    <properties>
      <property name="toplink.ddl-generation" 
                value="drop-and-create-tables"/>
    </properties>
  </persistence-unit>
</persistence>注意到transaction-type屬性為JTA,並透過<jta-data-source>設置容器端管理的Data Source之JNDI名稱,這必須在容器端先定好,JDBC資源與Connection Pool等。
接著來寫個Servlet客戶端:
- UserAdmin.java
package onlyfun.caterpillar;
import java.io.*;
import java.util.logging.*;
import javax.naming.*;
import javax.rmi.PortableRemoteObject;
import javax.servlet.*;
import javax.servlet.http.*;
public class UserAdmin extends HttpServlet {    
    protected void processRequest(HttpServletRequest request, 
                                HttpServletResponse response)
                                    throws ServletException, IOException {
        
        String name = request.getParameter("name");
        String age = request.getParameter("age");
        
        User user = new User();
        user.setName(name);
        user.setAge(new Long(Long.parseLong(age)));
        
        response.setContentType("text/html;charset=UTF-8");
        PrintWriter out = response.getWriter();
        try {
            InitialContext context = new InitialContext();
            Object obj = context.lookup(
                    "onlyfun.caterpillar.EntitySessionRemote");
            EntitySessionRemote entitySession = (EntitySessionRemote) 
               PortableRemoteObject.narrow(obj, EntitySessionRemote.class);
            
            entitySession.save(user);
            user = entitySession.findById(new Long(2));
            
            out.println(user.getName() + " saved...");
            entitySession.clearup();
        } catch (NamingException ex) {
            Logger.getLogger(UserAdmin.class.getName())
                    .log(Level.SEVERE, null, ex);
        } finally { 
            out.close();
        }
    } 
    protected void doGet(HttpServletRequest request, 
                         HttpServletResponse response)
                                  throws ServletException, IOException {
        processRequest(request, response);
    } 
    protected void doPost(HttpServletRequest request, 
                          HttpServletResponse response)
                                 throws ServletException, IOException {
        processRequest(request, response);
    }
}您可以使用請求參數name與age指定要儲存的使用者名稱與年紀,程式中透過JNDI Lookup來查找Stateful Session Bean,並操作對應的方法來儲存或取得使用者的資料。

