若
您以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:
package onlyfun.caterpillar;
import javax.ejb.Remote;
@Remote public interface EntitySessionRemote { public void save(User user); public User findById(Long id); public void clearup(); }
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的部份:
<?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客戶端:
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,並操作對應的方法來儲存或取得使用者的資料。
|