細(xì)心!用心!耐心!

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

          BlogJava 聯(lián)系 聚合 管理
            1 Posts :: 196 Stories :: 10 Comments :: 0 Trackbacks
          JPA EntityManager詳解(一)
          持久化上下文(Persistence Contexts)的相關(guān)知識(shí),內(nèi)容包括如何從Java EE容器中創(chuàng)建EntityManager對(duì)象、如何從Java SE中創(chuàng)建EntityManager對(duì)象、持久化上下文與事務(wù)(Transction)的關(guān)系,以及實(shí)體管理器工廠(Entity Manager Factory)的相關(guān)內(nèi)容。
          通過本章的學(xué)習(xí),讀者將深入掌握J(rèn)PA中有關(guān)持久化上下文、事務(wù)處理的相關(guān)知識(shí),從而能夠更加深入地應(yīng)用JPA。


          11.1 獲得EntityManager對(duì)象

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


          11.1.1  Java EE環(huán)境與J2SE環(huán)境

          在詳細(xì)講述EntityManager對(duì)象之前,讀者首先要分清楚兩個(gè)概念,即Java EE環(huán)境與J2SE環(huán)境。因?yàn)樵诒菊潞竺娴膶W(xué)習(xí)中要經(jīng)常提到這兩個(gè)概念,所以讀者一定要先理解它們,為以后的學(xué)習(xí)打好基礎(chǔ)。


          — Java EE環(huán)境,包括EJB容器和Web容器。

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

          (2)EJB容器:運(yùn)行在EJB組件的容器,提供EJB組件的狀態(tài)管理、事務(wù)管理、線程管理、遠(yuǎn)程數(shù)據(jù)資源訪問、連接管理和安全性管理等系統(tǒng)級(jí)服務(wù)。例如JBoss為EJB容器和Web容器(Web容器是集成了Tomcat)結(jié)合。

          部署在EJB容器中的JAR包都可以認(rèn)為是運(yùn)行在EJB容器中。但JBoss中的Web應(yīng)用,比如war包中的類就不是運(yùn)行在EJB容器中,而是運(yùn)行在Web容器中。

          — J2SE環(huán)境

          最普通Java運(yùn)行環(huán)境,例如一個(gè)HelloWorld的Java程序就是運(yùn)行在J2SE的環(huán)境中,通常使用main入口方法作為程序啟動(dòng)的觸發(fā)。

          如圖11-1所示,它說明了Java EE與J2SE環(huán)境的關(guān)系。

          11.1.2  兩種類型的EntityManager對(duì)象

          根據(jù)EntityManager對(duì)象的管理方式,可以有以下兩種類型。

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

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

          — 應(yīng)用托管的(application-managed)EntityManager對(duì)象

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

          理想狀態(tài)下,最好是選用容器托管的EntityManager對(duì)象的方式,但在特殊的環(huán)境下,還是需要使用應(yīng)用托管的EntityManager對(duì)象這種方式。

          正是因?yàn)閼?yīng)用托管的EntityManager對(duì)象的連接釋放、事務(wù)控制比較復(fù)雜,所以在使用時(shí)涉及的相關(guān)內(nèi)容比較多,這些內(nèi)容將在本章后面部分詳細(xì)講述,這里讀者應(yīng)對(duì)兩種方式有一個(gè)大致的了解,兩種EntityManager對(duì)象類型的比較如表11-1所示。

          表11-1  容器托管與應(yīng)用托管的EntityManager對(duì)象對(duì)比

          比較內(nèi)容

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

          應(yīng)用托管的(application-managed)EntityManager對(duì)象

          獲得方式

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

          EntityManagerFactory創(chuàng)建

          支持事務(wù)

          JTA

          JTA、RESOURCE_LOCAL

          運(yùn)行環(huán)境

          EJB容器

          EJB容器、Web容器、J2SE環(huán)境

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

          容器托管的EntityManager對(duì)象只能運(yùn)行在EJB容器中。所以可以這樣理解,只有在EJB-JAR包中,才可以獲得容器托管的EntityManager對(duì)象,否則只能獲得應(yīng)用托管的EntityManager對(duì)象。

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

          11.1.3.1  通過@PersistenceContext注釋注入

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

          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. }  


          在使用此種方式創(chuàng)建EntityManager對(duì)象時(shí),需要注意以下幾個(gè)問題。

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

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


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

          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可以設(shè)置創(chuàng)建EntityManager對(duì)象時(shí),持久化上下文的作用范圍,它的意義在于對(duì)有狀態(tài)的Bean(Stateless Bean)可以跨事務(wù)操作實(shí)體。它主要有兩種方式,定義如下所示。
          Java代碼
          1. public enum PersistenceContextType {  
          2.   
          3.     TRANSACTION,  
          4.   
          5.     EXTENDED  
          6.   
          7. }  


          默認(rèn)情況下使用TRANSACTION,有關(guān)TRANSACTION方式和EXTENDED方式創(chuàng)建EntityManager對(duì)象的異同,將在下文中詳細(xì)講述,這里讀者簡(jiǎn)單了解一下即可。

          11.1.3.2  通過JNDI的方式獲得

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

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

          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  應(yīng)用托管的(application-managed)EntityManager對(duì)象

          應(yīng)用托管的EntityManager對(duì)象,不僅可以在Java EE環(huán)境中獲得,也可以應(yīng)用在J2SE的環(huán)境中。但無論是在什么情況下獲得的EntityManager對(duì)象,都是通過實(shí)體管理器工廠 (EntityManagerFactory)對(duì)象創(chuàng)建的。所以如何獲得應(yīng)用托管的EntityManager對(duì)象關(guān)鍵是 EntityManagerFactory對(duì)象如何獲得。

          下面就分別講述在EJB容器、Web容器和J2SE環(huán)境中如何獲得EntityManagerFactory對(duì)象。

          11.1.4.1  EJB容器中獲得

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

          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.         /**創(chuàng)建EntityManager對(duì)象*/  
          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.         /**關(guān)閉EntityManager */  
          26.   
          27.         em.close();  
          28.   
          29.         return result;  
          30.   
          31.     }  
          32.   
          33. }  

          通過以上的EntityManager對(duì)象代碼,可以總結(jié)出以下幾個(gè)問題。

          — 應(yīng)用托管的EntityManager對(duì)象,要在代碼中手動(dòng)地創(chuàng)建和關(guān)閉,例如下面代碼所示。

          EntityManager em = emf.createEntityManager();

          /**其他的業(yè)務(wù)邏輯*/

          em.close();

          這點(diǎn)正是與容器托管的EntityManager對(duì)象的最大不同之處。事實(shí)上,容器托管的EntityManager對(duì)象,它的創(chuàng)建和關(guān)閉是由容器負(fù)責(zé)管理的,所以不需要編寫代碼來控制。

          — 應(yīng)用托管的EntityManager對(duì)象,都是通EntityManagerFactory對(duì)象來創(chuàng)建的。在容器中可以通過使用注入@PersistenceUnit注釋的方法實(shí)現(xiàn),它的定義如下所示。

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


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

          11.1.4.2  Web容器中獲得

          在Web容器中,EntityManagerFactory對(duì)象也可以通過使用注入@PersistenceUnit注釋獲得。例如,下面代碼為在 Servlet中,獲得應(yīng)用托管的EntityManager對(duì)象的方法。 /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.             /**創(chuàng)建EntityManager 對(duì)象*/  
          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.                 /**關(guān)閉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 張金鵬 閱讀(56293) 評(píng)論(1)  編輯  收藏 所屬分類: JPA

          Feedback

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

          主站蜘蛛池模板: 庄浪县| 花莲市| 滦南县| 奇台县| 汪清县| 南京市| 桐乡市| 永宁县| 大兴区| 东平县| 萨迦县| 青冈县| 崇明县| 拜泉县| 朔州市| 井陉县| 纳雍县| 韶山市| 吉林市| 喀什市| 南华县| 石首市| 平乡县| 古浪县| 九江县| 且末县| 隆回县| 屏东市| 永修县| 紫阳县| 永安市| 香格里拉县| 彝良县| 汽车| 台州市| 东山县| 进贤县| 瑞安市| 聊城市| 上杭县| 大连市|