細心!用心!耐心!

          吾非文人,乃市井一俗人也,讀百卷書,跨江河千里,故申城一游; 一兩滴辛酸,三四年學業,五六點粗墨,七八筆買賣,九十道人情。

          BlogJava 聯系 聚合 管理
            1 Posts :: 196 Stories :: 10 Comments :: 0 Trackbacks
          JPA EntityManager詳解(一)
          持久化上下文(Persistence Contexts)的相關知識,內容包括如何從Java EE容器中創建EntityManager對象、如何從Java SE中創建EntityManager對象、持久化上下文與事務(Transction)的關系,以及實體管理器工廠(Entity Manager Factory)的相關內容。
          通過本章的學習,讀者將深入掌握JPA中有關持久化上下文、事務處理的相關知識,從而能夠更加深入地應用JPA。


          11.1 獲得EntityManager對象

          那么如何獲得EntityManager對象呢?這又是JPA中另外一個很重要的問題。


          11.1.1  Java EE環境與J2SE環境

          在詳細講述EntityManager對象之前,讀者首先要分清楚兩個概念,即Java EE環境與J2SE環境。因為在本章后面的學習中要經常提到這兩個概念,所以讀者一定要先理解它們,為以后的學習打好基礎。


          — Java EE環境,包括EJB容器和Web容器。

          (1)Web容器:只運行Web應用的容器,例如Tomcat就是開源的Web容器,它可以運行JSP、Servlet等。

          (2)EJB容器:運行在EJB組件的容器,提供EJB組件的狀態管理、事務管理、線程管理、遠程數據資源訪問、連接管理和安全性管理等系統級服務。例如JBoss為EJB容器和Web容器(Web容器是集成了Tomcat)結合。

          部署在EJB容器中的JAR包都可以認為是運行在EJB容器中。但JBoss中的Web應用,比如war包中的類就不是運行在EJB容器中,而是運行在Web容器中。

          — J2SE環境

          最普通Java運行環境,例如一個HelloWorld的Java程序就是運行在J2SE的環境中,通常使用main入口方法作為程序啟動的觸發。

          如圖11-1所示,它說明了Java EE與J2SE環境的關系。

          11.1.2  兩種類型的EntityManager對象

          根據EntityManager對象的管理方式,可以有以下兩種類型。

          — 容器托管的(container-managed)EntityManager對象

          容器托管的EntityManager對象最簡單,程序員不需要考慮EntityManager連接的釋放,以及事務等復雜的問題,所有這些都交 給容器去管理。容器托管的EntityManager對象必須在EJB容器中運行,而不能在Web容器和J2SE的環境中運行。本書前面講述的 EntityManager對象都是通過注入 @PersistenceContext注釋來獲得的,其實,這種獲得EntityManager對象的方式就是容器托管的。

          — 應用托管的(application-managed)EntityManager對象

          應用托管的EntityManager對象,程序員需要手動地控制它的釋放和連接、手動地控制事務等。但這種獲得應用托管的 EntityManager對象的方式,不僅可以在EJB容器中應用,也可以使 JPA脫離EJB容器,而與任何的Java環境集成,比如說Web容器、J2SE環境等。所以從某種角度上來說,這種方式是JPA能夠獨立于EJB環境運 行的基礎。

          理想狀態下,最好是選用容器托管的EntityManager對象的方式,但在特殊的環境下,還是需要使用應用托管的EntityManager對象這種方式。

          正是因為應用托管的EntityManager對象的連接釋放、事務控制比較復雜,所以在使用時涉及的相關內容比較多,這些內容將在本章后面部分詳細講述,這里讀者應對兩種方式有一個大致的了解,兩種EntityManager對象類型的比較如表11-1所示。

          表11-1  容器托管與應用托管的EntityManager對象對比

          比較內容

          容器托管的(container-managed)EntityManager對象

          應用托管的(application-managed)EntityManager對象

          獲得方式

          兩種方式:1 @PersistenceContex注入 2 JNDI獲得

          EntityManagerFactory創建

          支持事務

          JTA

          JTA、RESOURCE_LOCAL

          運行環境

          EJB容器

          EJB容器、Web容器、J2SE環境

          11.1.3  容器托管的(container-managed)EntityManager對象

          容器托管的EntityManager對象只能運行在EJB容器中。所以可以這樣理解,只有在EJB-JAR包中,才可以獲得容器托管的EntityManager對象,否則只能獲得應用托管的EntityManager對象。

          在EJB容器中獲得EntityManager對象主要有兩種方式,即@PersistenceContext注釋注入和JNDI方式獲得。

          11.1.3.1  通過@PersistenceContext注釋注入

          這種方式獲得EntityManager對象最為常用,例如下面代碼所示。

          1. @Stateless  
          2.   
          3. public class CustomerService implements ICustomerService {  
          4.   
          5.     @PersistenceContext(unitName = "jpaUnit")  
          6.   
          7.     private EntityManager entityManager;  
          8.   
          9.     public List<CustomerEO> findAllCustomers() {  
          10.   
          11.         Query query = entityManager.createQuery("SELECT c FROM CustomerEO c");  
          12.   
          13.         List<CustomerEO> result = query.getResultList();  
          14.   
          15.         for (CustomerEO c : result) {  
          16.   
          17.             System.out.println(c.getId()+","+c.getName());  
          18.   
          19.         }  
          20.   
          21.         return result;  
          22.   
          23.     }  
          24.   
          25. }  


          在使用此種方式創建EntityManager對象時,需要注意以下幾個問題。

          — @PersistenceContext注釋中,其中unitName為persistence.xml文件中<persistence-unit>元素中的屬性“name”的值,表示要初始化哪個持久化單元,如下所示。

          Xml代碼
          1. <persistence>  
          2.   
          3.     <persistence-unit name="jpaUnit" transaction-type="JTA">  
          4.   
          5.     </persistence-unit>  
          6.   
          7. </persistence>  


          — @PersistenceContext注釋中還可以配置其他的設置,它的定義如下所示。

          Java代碼
          1. @Target({TYPE, METHOD, FIELD}) @Retention(RUNTIME)  
          2.   
          3. public @interface PersistenceContext{  
          4.   
          5.     String name() default "";  
          6.   
          7.     String unitName() default "";  
          8.   
          9.     PersistenceContextType type default TRANSACTION;  
          10.   
          11.     PersistenceProperty[] properties() default {};  
          12.   
          13. }  


          — 其中PersistenceContextType可以設置創建EntityManager對象時,持久化上下文的作用范圍,它的意義在于對有狀態的Bean(Stateless Bean)可以跨事務操作實體。它主要有兩種方式,定義如下所示。
          Java代碼
          1. public enum PersistenceContextType {  
          2.   
          3.     TRANSACTION,  
          4.   
          5.     EXTENDED  
          6.   
          7. }  


          默認情況下使用TRANSACTION,有關TRANSACTION方式和EXTENDED方式創建EntityManager對象的異同,將在下文中詳細講述,這里讀者簡單了解一下即可。

          11.1.3.2  通過JNDI的方式獲得

          如果指定了@PersistenceContext注釋中的name值,則設置了持久化上下文的JNDI名稱。通過SessionContext可以創建EntityManager對象。

          例如,下面代碼為通過JNDI方式獲得EntityManager對象。

          1. @Stateless  
          2.   
          3. @PersistenceContext(name="jpa")  
          4.   
          5. public class CustomerService implements ICustomerService {  
          6.   
          7.     @Resource  
          8.   
          9.     SessionContext ctx;  
          10.   
          11.     public List<CustomerEO> findAllCustomers() {  
          12.   
          13.         EntityManager entityManager = (EntityManager) ctx.lookup("jpa");  
          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.         return result;  
          26.   
          27.     }  
          28.   
          29. }  


          11.1.4  應用托管的(application-managed)EntityManager對象

          應用托管的EntityManager對象,不僅可以在Java EE環境中獲得,也可以應用在J2SE的環境中。但無論是在什么情況下獲得的EntityManager對象,都是通過實體管理器工廠 (EntityManagerFactory)對象創建的。所以如何獲得應用托管的EntityManager對象關鍵是 EntityManagerFactory對象如何獲得。

          下面就分別講述在EJB容器、Web容器和J2SE環境中如何獲得EntityManagerFactory對象。

          11.1.4.1  EJB容器中獲得

          在EJB容器中,EntityManagerFactory對象可以通過使用注入@PersistenceUnit注釋獲得,例如下面代碼為在EJB容器中,獲得應用托管的EntityManager對象的方法。

          1. @Stateless  
          2.   
          3. public class CustomerService implements ICustomerService {  
          4.   
          5.     @PersistenceUnit(unitName="jpaUnit")  
          6.   
          7.     private EntityManagerFactory emf;  
          8.   
          9.     public List<CustomerEO> findAllCustomers() {  
          10.   
          11.         /**創建EntityManager對象*/  
          12.   
          13.         EntityManager em = emf.createEntityManager();  
          14.   
          15.         Query query = em.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.         em.close();  
          28.   
          29.         return result;  
          30.   
          31.     }  
          32.   
          33. }  

          通過以上的EntityManager對象代碼,可以總結出以下幾個問題。

          — 應用托管的EntityManager對象,要在代碼中手動地創建和關閉,例如下面代碼所示。

          EntityManager em = emf.createEntityManager();

          /**其他的業務邏輯*/

          em.close();

          這點正是與容器托管的EntityManager對象的最大不同之處。事實上,容器托管的EntityManager對象,它的創建和關閉是由容器負責管理的,所以不需要編寫代碼來控制。

          — 應用托管的EntityManager對象,都是通EntityManagerFactory對象來創建的。在容器中可以通過使用注入@PersistenceUnit注釋的方法實現,它的定義如下所示。

          1. @Target({TYPE, METHOD, FIELD}) @Retention(RUNTIME)  
          2.   
          3. public @interface PersistenceUnit{  
          4.   
          5.     String name() default "";  
          6.   
          7.     String unitName() default "";  
          8.   


          其中,屬性unitName為persistence.xml文件中<persistence-unit>元素中的屬性“name”的值,表示要初始化哪個持久化單元,與@PersistenceContext注釋中unitName屬性相同。

          11.1.4.2  Web容器中獲得

          在Web容器中,EntityManagerFactory對象也可以通過使用注入@PersistenceUnit注釋獲得。例如,下面代碼為在 Servlet中,獲得應用托管的EntityManager對象的方法。 /syntaxhighlighter/clipboard_new.swf">
          1. public class TestServlet extends HttpServlet {  
          2.   
          3.     @PersistenceUnit(unitName = "jpaUnit")  
          4.   
          5.     private EntityManagerFactory emf;  
          6.   
          7.     public TestServlet() {  
          8.   
          9.         super();  
          10.   
          11.     }  
          12.   
          13.     public void doGet(HttpServletRequest request, HttpServletResponse response)  
          14.   
          15.             throws ServletException, IOException {  
          16.   
          17.         doPost(request, response);  
          18.   
          19.     }  
          20.   
          21.     public void doPost(HttpServletRequest request, HttpServletResponse response)  
          22.   
          23.             throws ServletException, IOException {  
          24.   
          25.         response.setContentType("text/html");  
          26.   
          27.         PrintWriter out = response.getWriter();  
          28.   
          29.         out.println("<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.01 Transitional //EN\">");  
          30.   
          31.         out.println("<HTML>");  
          32.   
          33.         out.println("  <HEAD><TITLE>A Servlet</TITLE></HEAD>");  
          34.   
          35.         out.println("  <BODY>");  
          36.   
          37.         if (emf != null) {  
          38.   
          39.             /**創建EntityManager 對象*/  
          40.   
          41.             EntityManager entityManager = emf.createEntityManager();  
          42.   
          43.             try {  
          44.   
          45.                 Query query = entityManager  
          46.   
          47.                         .createQuery("SELECT c FROM CustomerEO c");  
          48.   
          49.                 List<CustomerEO> result = query.getResultList();  
          50.   
          51.                 for (CustomerEO c : result) {  
          52.   
          53.                     System.out.println(c.getId() + "," + c.getName());  
          54.   
          55.                 }  
          56.   
          57.             } finally {  
          58.   
          59.                 /**關閉EntityManager*/  
          60.   
          61.                 entityManager.close();  
          62.   
          63.             }  
          64.   
          65.         }  
          66.   
          67.         out.println("  </BODY>");  
          68.   
          69.         out.println("</HTML>");  
          70.   
          71.         out.flush();  
          72.   
          73.         out.close();  
          74.   
          75.     }  
          76.   
          77. }  
          posted on 2012-06-15 21:34 張金鵬 閱讀(56281) 評論(1)  編輯  收藏 所屬分類: JPA

          Feedback

          # re: JPA EntityManager詳解(一) 2016-03-18 13:50 謝謝
          版主,如果利用entityManager進行查詢,如何在sql里邊傳參,防注入的那種  回復  更多評論
            

          主站蜘蛛池模板: 泗水县| 和田县| 大田县| 北安市| 宜都市| 崇左市| 西宁市| 常德市| 郁南县| 禹州市| 招远市| 卓尼县| 鹤山市| 寿阳县| 墨竹工卡县| 吉首市| 桐乡市| 桐梓县| 连南| 南康市| 华蓥市| 麦盖提县| 凤台县| 乐安县| 蓝山县| 东乡族自治县| 汾阳市| 阳谷县| 龙游县| 荔浦县| 民权县| 江阴市| 邢台市| 二连浩特市| 定南县| 库伦旗| 凤庆县| 祁阳县| 陈巴尔虎旗| 印江| 丽水市|