在 Servlet 中直接使用 JPA


若您要直接在Servlet中使用JPA,要記得的是,EntityManager不是Thread-safe,所以切記,不可直接將EntityManager注入Servlet中成為物件成員之一,Servlet被共用存取的情況下,會有資料共用存取的問題。

若您要在Servlet中直接使用JPA,有兩種方式可以進行,一是透過在類別上宣告@PersistenceContext並設定JNDI名稱來查找, 二是透過@PersistenceUnit注入EntityManagerFactory並用其取得EntityManager,前者的方式為 Container-Managed Entity,後者的方式則為Application-Managed EntityManager。

第一個方法若以 第一個 JPA(容器管理) 中的User實體為例,您可以如下撰寫Servlet:
  • UserAdmin.java
package onlyfun.caterpillar;

import java.io.*;

import java.util.logging.*;
import javax.annotation.*;
import javax.naming.*;
import javax.persistence.*;
import javax.rmi.PortableRemoteObject;
import javax.servlet.*;
import javax.servlet.http.*;
import javax.transaction.*;

@PersistenceContext(name="sample/EntityManager", unitName="sample")
public class UserAdmin extends HttpServlet {
@Resource
private UserTransaction ut;

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();
EntityManager entityManager = null;

try {
InitialContext context = new InitialContext();
Object obj = context.lookup(
"java:comp/env/sample/EntityManager");
entityManager = (EntityManager)
PortableRemoteObject.narrow(obj, EntityManager.class);

ut.begin();
entityManager.persist(user);
ut.commit();

} catch (Exception ex) {
Logger.getLogger(UserAdmin.class.getName())
.log(Level.SEVERE, null, ex);
} finally {
entityManager.close();
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);
}
}

在您的Web應用程式可存取的Classpath路徑中(例如WEB-INF/classes下),要建立META-INF/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>

@PersistenceContext的name名稱將作為JNDI查找名稱,從unitName設定得知,實際上查找到的 是<persistence-unit>中對應的sample定義,Servlet中使用JNDI查找name名稱以取得 EntityManager實例,並透過注入的UserTransaction啟用交易,在交易中進行持久化動作。

若不在類別上使用@PersistenceContext,您也可以在web.xml中加入以下的定義:
....
    <persistence-context-ref>
        <persistence-context-ref-name>
            sample/EntityManager
        </persistence-context-ref>
        <persistence-unit-name>
            sample
        </persistence-unit-name>
    </persistence-context-ref>
....

第一個方法直接使用@PersistenceUnit注入EntityManagerFactory,例如:
  • UserAdmin.java
package onlyfun.caterpillar;

import java.io.*;

import java.util.logging.*;
import javax.annotation.*;
import javax.persistence.*;
import javax.servlet.*;
import javax.servlet.http.*;
import javax.transaction.*;

public class UserAdmin extends HttpServlet {
@PersistenceUnit(unitName="sample")
private EntityManagerFactory emFactory;

@Resource
private UserTransaction ut;
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();
EntityManager entityManager = null;

try {
entityManager = emFactory.createEntityManager();

ut.begin();
entityManager.persist(user);
ut.commit();

} catch (Exception ex) {
Logger.getLogger(UserAdmin.class.getName())
.log(Level.SEVERE, null, ex);
} finally {
entityManager.close();
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);
}
}

類似於 第一個 JPA(單機客戶端) 中的例子,您從注入的EntityManagerFactory中建立EntityManager,之後利用其進行持久化物件或其它的操作。