JPA EntityManager详解(二)

本文介绍了如何在使用JPA的Web容器中,通过ThreadLocal类解决EntityManager对象的线程安全问题。通过创建EntityManagerHelper类,实现了线程独立的EntityManager对象获取、关闭、事务管理等功能,确保了每个线程都能独立操作数据库资源,避免了Servlet非线程安全的限制。
摘要由CSDN通过智能技术生成
★ 提示 ★

目前JBoss 4.2集成了的Tomcat版本为5.5,但Tomcat 6.0以后的版本中才支持使用注释,所以如果将本例中Servlet运行在JBoss 4.2中,并不能获得EntityManagerFactory对象;但在符合J2EE 5.0的服务器中,这样运行是可以的。
虽然在目前JBoss 4.2版本中不支持使用注释,但可以通过另一种方式来获得应用托管的EntityManager对象。代码如下所示。
1. public class TestServlet extends HttpServlet {  
2.   
3.     private EntityManagerFactory emf;  
4.   
5.     public TestServlet() {  
6.   
7.         super();  
8.   
9.     }  
10.   
11.     public void doGet(HttpServletRequest request, HttpServletResponse response)  
12.   
13.             throws ServletException, IOException {  
14.   
15.         doPost(request, response);  
16.   
17.     }  
18.   
19.     public void doPost(HttpServletRequest request, HttpServletResponse response)  
20.   
21.             throws ServletException, IOException {  
22.   
23.         response.setContentType("text/html");  
24.   
25.         PrintWriter out = response.getWriter();  
26.   
27.         out.println("<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.01 Transitional //EN\">");  
28.   
29.         out.println("<HTML>");  
30.   
31.         out.println("  <HEAD><TITLE>A Servlet</TITLE></HEAD>");  
32.   
33.         out.println("  <BODY>");  
34.   
35.         if (emf != null) {  
36.   
37.             /**创建EntityManager 对象*/  
38.   
39.             EntityManager entityManager = emf.createEntityManager();  
40.   
41.             try {  
42.   
43.                 Query query = entityManager  
44.   
45.                         .createQuery("SELECT c FROM CustomerEO c");  
46.   
47.                 List<CustomerEO> result = query.getResultList();  
48.   
49.                 for (CustomerEO c : result) {  
50.   
51.                     System.out.println(c.getId() + "," + c.getName());  
52.   
53.                 }  
54.   
55.             } finally {  
56.   
57.                 /**关闭EntityManager*/  
58.   
59.                 entityManager.close();  
60.   
61.             }  
62.   
63.         }  
64.   
65.         out.println("  </BODY>");  
66.   
67.         out.println("</HTML>");  
68.   
69.         out.flush();  
70.   
71.         out.close();  
72.   
73.     }  
74.   
75.     /**Servlet初始化时,创建EntityManagerFactory 对象*/  
76.   
77.     public void init() throws ServletException {  
78.   
79.         if (emf == null) {  
80.   
81.             emf = Persistence.createEntityManagerFactory("jpaUnit");  
82.   
83.         }  
84.   
85.     }  
86.   
87.     /**Servlet销毁时,关闭EntityManagerFactory对象*/  
88.   
89.     public void destroy() {  
90.   
91.         if (emf.isOpen())  
92.   
93.             emf.close();  
94.   
95.     }  
96.   
97. }  

public class TestServlet extends HttpServlet {

private EntityManagerFactory emf;

public TestServlet() {

super();

}

public void doGet(HttpServletRequest request, HttpServletResponse response)

throws ServletException, IOException {

doPost(request, response);

}

public void doPost(HttpServletRequest request, HttpServletResponse response)

throws ServletException, IOException {

response.setContentType("text/html");

PrintWriter out = response.getWriter();

out.println("<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.01 Transitional //EN\">");

out.println("<HTML>");

out.println("  <HEAD><TITLE>A Servlet</TITLE></HEAD>");

out.println("  <BODY>");

if (emf != null) {

/**创建EntityManager 对象*/

EntityManager entityManager = emf.createEntityManager();

try {

Query query = entityManager

.createQuery("SELECT c FROM CustomerEO c");

List<CustomerEO> result = query.getResultList();

for (CustomerEO c : result) {

System.out.println(c.getId() + "," + c.getName());

}

} finally {

/**关闭EntityManager*/

entityManager.close();

}

}

out.println("  </BODY>");

out.println("</HTML>");

out.flush();

out.close();

}

/**Servlet初始化时,创建EntityManagerFactory 对象*/

public void init() throws ServletException {

if (emf == null) {

emf = Persistence.createEntityManagerFactory("jpaUnit");

}

}

/**Servlet销毁时,关闭EntityManagerFactory对象*/

public void destroy() {

if (emf.isOpen())

emf.close();

}

}



使用这种方式创建EntityManagerFactory对象需要注意以下几个问题。

可以看到,这里的EntityManagerFactory对象不是通过注入获得的,而是通过Persistence类中的静态方法createEntityManagerFactory来创建的。

— 正因为EntityManagerFactory对象是手动创建的,所以在不再使用时,一定要调用close()方法手动关闭。

11.1.4.3  J2SE环境中获得

在J2SE环境中,获得应用托管的EntityManager对象只能通过手动创建的方式,而不能使用注释的方式,与Web容器中不使用注释的方法相同,都是通过Persistence类中createEntityManagerFactory来创建的。

例如,下面代码为J2SE环境中获得应用托管EntityManager对象的方法。

1. public class CustomerClient {  
2.   
3.     public static void main(String[] args) {  
4.   
5.         /** 创建EntityManagerFactory对象 */  
6.   
7.         EntityManagerFactory emf = Persistence  
8.   
9.                 .createEntityManagerFactory("jpaUnit");  
10.   
11.         /** 创建entityManager对象 */  
12.   
13.         EntityManager entityManager = emf.createEntityManager();  
14.   
15.         Query query = entityManager.createQuery("SELECT c FROM CustomerEO c");  
16.   
17.         List<CustomerEO> result = query.getResultList();  
18.   
19.         for (CustomerEO c : result) {  
20.   
21.             System.out.println(c.getId() + "," + c.getName());  
22.   
23.         }  
24.   
25.         /** 关闭entityManager对象 */  
26.   
27.         entityManager.close();  
28.   
29.         /** 关闭EntityManagerFactory对象 */  
30.   
31.         emf.close();  
32.   
33.     }  
34.   
35. }  

public class CustomerClient {

public static void main(String[] args) {

/** 创建EntityManagerFactory对象 */

EntityManagerFactory emf = Persistence

.createEntityManagerFactory("jpaUnit");

/** 创建entityManager对象 */

EntityManager entityManager = emf.createEntityManager();

Query query = entityManager.createQuery("SELECT c FROM CustomerEO c");

List<CustomerEO> result = query.getResultList();

for (CustomerEO c : result) {

System.out.println(c.getId() + "," + c.getName());

}

/** 关闭entityManager对象 */

entityManager.close();

/** 关闭EntityManagerFactory对象 */

emf.close();

}

}
但是,在J2SE环境中使用JPA需要将实现的JPA的第三方类包和数据库的驱动包,设置到当前的运行环境下。

例如,在Eclipse中创建一个Java项目,需要将JPA实现者的类库(这里以Hibernate为例)和MySQL的数据库连接包添加到构建路径中,如图11-2所示。

11.1.5  ThreadLocal的使用

对于在Web容器中使用EntityManager对象,这里需要做一些改进,才能更安全。读者应该了解,Servlet是非线程安全的,所以需要改变获得EntityManager对象的方式,这里笔者建议使用ThreadLocal类。

ThreadLocal就是为每一个使用某变量的线程都提供一个该变量值的副本,使每一个线程都可以独立地改变自己的副本,而不会和其他线程的副本冲突。从线程的角度看,就好像每一个线程都完全拥有一个该变量,这就解决了Servlet非线程安全的问题。

首先编写一个EntityManagerHelper类,代码如下所示。
1. public class EntityManagerHelper {  
2.   
3.      
4.   
5.     private static final EntityManagerFactory emf;  
6.   
7.     private static final ThreadLocal<EntityManager> threadLocal;  
8.   
9.      
10.   
11.     /**初始化*/  
12.   
13.     static {  
14.   
15.         emf = Persistence.createEntityManagerFactory("jpaUnit");         
16.   
17.         threadLocal = new ThreadLocal<EntityManager>();  
18.   
19.     }  
20.   
21.      
22.   
23.     /**通过threadLocal 获得EntityManager 对象*/  
24.   
25.     public static EntityManager getEntityManager() {  
26.   
27.         EntityManager manager = threadLocal.get();       
28.   
29.         if (manager == null || !manager.isOpen()) {  
30.   
31.             manager = emf.createEntityManager();  
32.   
33.             threadLocal.set(manager);  
34.   
35.         }  
36.   
37.         return manager;  
38.   
39.     }  
40.   
41.      
42.   
43.     /**关闭EntityManager 对象*/  
44.   
45.     public static void closeEntityManager() {  
46.   
47.         EntityManager em = threadLocal.get();  
48.   
49.         threadLocal.set(null);  
50.   
51.         if (em != null) em.close();  
52.   
53.     }  
54.   
55.      
56.   
57.     public static void beginTransaction() {  
58.   
59.     getEntityManager().getTransaction().begin();  
60.   
61.     }  
62.   
63.      
64.   
65.     public static void commit() {  
66.   
67.     getEntityManager().getTransaction().commit();  
68.   
69.     }   
70.   
71.      
72.   
73.     public static Query createQuery(String query) {  
74.   
75.         return getEntityManager().createQuery(query);  
76.   
77.     }  
78.   
79.      
80.   
81. }  

public class EntityManagerHelper {



private static final EntityManagerFactory emf;

private static final ThreadLocal<EntityManager> threadLocal;



/**初始化*/

static {

emf = Persistence.createEntityManagerFactory("jpaUnit");       

threadLocal = new ThreadLocal<EntityManager>();

}



/**通过threadLocal 获得EntityManager 对象*/

public static EntityManager getEntityManager() {

EntityManager manager = threadLocal.get();     

if (manager == null || !manager.isOpen()) {

manager = emf.createEntityManager();

threadLocal.set(manager);

}

return manager;

}



/**关闭EntityManager 对象*/

public static void closeEntityManager() {

EntityManager em = threadLocal.get();

threadLocal.set(null);

if (em != null) em.close();

}



public static void beginTransaction() {

getEntityManager().getTransaction().begin();

}



public static void commit() {

getEntityManager().getTransaction().commit();





public static Query createQuery(String query) {

return getEntityManager().createQuery(query);

}



}



这样经过改进后,在Servlet中创建EntityManager对象的方法修改为如下所示。

1. public class TestServlet extends HttpServlet {  
2.   
3.     public TestServlet() {  
4.   
5.         super();  
6.   
7.     }  
8.   
9.     public void doPost(HttpServletRequest request, HttpServletResponse response)  
10.   
11.             throws ServletException, IOException {  
12.   
13.             EntityManager entityManager = EntityManagerHelper.getEntityManager();  
14.   
15.             try {  
16.   
17.                 Query query = entityManager  
18.   
19.                         .createQuery("SELECT c FROM CustomerEO c");  
20.   
21.                 List<CustomerEO> result = query.getResultList();  
22.   
23.                 for (CustomerEO c : result) {  
24.   
25.                     System.out.println(c.getId() + "," + c.getName());  
26.   
27.                 }  
28.   
29.             } finally {  
30.   
31.                 /**关闭EntityManager*/  
32.   
33.                 EntityManagerHelper.closeEntityManager();  
34.   
35.             }  
36.   
37.     }  
38.   
39. }
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值