JPA EntityManager詳解(二)
★ 提示 ★ 目前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. } |