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ì)象最為常用,例如下面代碼所示。
在使用此種方式創(chuàng)建EntityManager對(duì)象時(shí),需要注意以下幾個(gè)問題。 — @PersistenceContext注釋中,其中unitName為persistence.xml文件中<persistence-unit>元素中的屬性“name”的值,表示要初始化哪個(gè)持久化單元,如下所示。
— @PersistenceContext注釋中還可以配置其他的設(shè)置,它的定義如下所示。
— 其中PersistenceContextType可以設(shè)置創(chuàng)建EntityManager對(duì)象時(shí),持久化上下文的作用范圍,它的意義在于對(duì)有狀態(tài)的Bean(Stateless Bean)可以跨事務(wù)操作實(shí)體。它主要有兩種方式,定義如下所示。
默認(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ì)象。
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ì)象的方法。
通過以上的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),它的定義如下所示。
其中,屬性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">
|