jpa開發(fā)手冊(cè).doc_第1頁
jpa開發(fā)手冊(cè).doc_第2頁
jpa開發(fā)手冊(cè).doc_第3頁
jpa開發(fā)手冊(cè).doc_第4頁
jpa開發(fā)手冊(cè).doc_第5頁
已閱讀5頁,還剩17頁未讀, 繼續(xù)免費(fèi)閱讀

下載本文檔

版權(quán)說明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請(qǐng)進(jìn)行舉報(bào)或認(rèn)領(lǐng)

文檔簡(jiǎn)介

JPA開發(fā)文檔1. 發(fā)展中的持久化技術(shù)11.1 JDBC11.2關(guān)系對(duì)象映射(Object Relational Mapping,ORM)21.3 Java數(shù)據(jù)對(duì)象(Java Data Object,JDO)21.4 Java Persistence API(JPA)22. JPA體系架構(gòu)3清單1在非Java EE環(huán)境使用JPA接口的例子5清單2在容器中運(yùn)行的JPA例子53. Entity Bean63.1定義對(duì)Entity中屬性變量的訪問63.2主鍵和實(shí)體標(biāo)識(shí)(Primary Key and Entity Identity)84. EntityManager94.1配置和獲得EntityManager94.2 Entity的生命周期和狀態(tài)104.3持久化Entity(Persist)114.4獲取Entity134.5更新Entity134.6刪除Entity144.7脫離/附合(Detach/Merge)145. JPA Query155.1 Query接口155.2簡(jiǎn)單查詢165.3使用參數(shù)查詢175.4排序(order by)175.5查詢部分屬性185.6查詢中使用構(gòu)造器(Constructor)185.7聚合查詢(Aggregation)195.8關(guān)聯(lián)(join)205.9比較Entity225.10批量更新(Batch Update)225.11批量刪除(Batch Remove)221. 發(fā)展中的持久化技術(shù)1.1 JDBC很多企業(yè)應(yīng)用的開發(fā)者選擇使用 JDBC管理關(guān)系型數(shù)據(jù)庫中的數(shù)據(jù)。JDBC支持處理大量的數(shù)據(jù),能夠保證數(shù)據(jù)的一致性,支持信息的并發(fā)訪問,提供 SQL查詢語言查找數(shù)據(jù)。JDBC所使用的關(guān)系模型不是為保存對(duì)象而設(shè)計(jì)的,因此迫使開發(fā)者選擇在處理持久數(shù)據(jù)時(shí)放棄面向?qū)ο缶幊?,或者自己去開發(fā)將面向?qū)ο筇匦裕ū热纾侯愔g的繼承)和關(guān)系型數(shù)據(jù)庫進(jìn)行映射的專有解決方案。1.2關(guān)系對(duì)象映射(Object Relational Mapping,ORM)ORM是目前完成對(duì)象和關(guān)系數(shù)據(jù)表之間的映射最好的一種技術(shù), 這些 ORM框架處理對(duì)象和關(guān)系數(shù)據(jù)庫之間的協(xié)調(diào)工作,將開發(fā)者從這部分工作中解脫出來,集中精力處理對(duì)象模型。阻礙 ORM發(fā)展的問題是,現(xiàn)有的每一種 ORM產(chǎn)品都有自己特有的 API,開發(fā)者只能將自己的代碼綁定到某一個(gè)框架提供商的接口上,這種狀況形成了廠商鎖定,意味著一旦該框架提供商無法解決系統(tǒng)中出現(xiàn)的嚴(yán)重錯(cuò)誤,或者因?yàn)槠渌脑蜣D(zhuǎn)而采用其它的框架,將會(huì)給開發(fā)者的企業(yè)應(yīng)用帶來極大的困難,唯一的解決辦法是重寫所有的持久化代碼。1.3 Java數(shù)據(jù)對(duì)象(Java Data Object,JDO)JDO是 Java EE標(biāo)準(zhǔn)中另外一個(gè)支持管理持久化數(shù)據(jù)的規(guī)范,JDO規(guī)范使用和 JPA非常類似的 API,只是通常是通過 JCA技術(shù)集成到應(yīng)用服務(wù)器上。但是 JDO是針對(duì)輕量級(jí)容器而設(shè)計(jì)的,不能夠支持容器級(jí)別的聲明式安全、事務(wù)特性,也無法對(duì)遠(yuǎn)程方法調(diào)用提供支持。1.4 Java Persistence API(JPA)EJB 3.0規(guī)范由三部分組成:EJB3.0 Simplified API、EJB核心規(guī)范(EJB Core Contracts and Requirements)和 JPA(Java Persistence API)。JPA規(guī)范部分詳細(xì)的介紹了 JPA中實(shí)體 Bean的定義,并介紹了實(shí)體 Bean支持的注釋、全新的查詢語言、實(shí)體管理接口、容器實(shí)現(xiàn)規(guī)范等內(nèi)容。JPA標(biāo)準(zhǔn)制定過程中充分吸收了目前已經(jīng)出現(xiàn)的所有持久化技術(shù)的所有優(yōu)點(diǎn),摒棄了它們存在的局限,使 JPA在簡(jiǎn)單易用、查詢能力等方面表現(xiàn)突出。 標(biāo)準(zhǔn)化JPA是 JCP組織發(fā)布的 Java EE標(biāo)準(zhǔn)之一,因此任何聲稱符合 JPA標(biāo)準(zhǔn)的框架都遵循同樣的架構(gòu),提供相同的訪問 API,這保證了基于 JPA開發(fā)的企業(yè)應(yīng)用能夠經(jīng)過少量的修改就能夠在不同的 JPA框架下運(yùn)行。 對(duì)容器級(jí)特性的支持JPA框架中支持大數(shù)據(jù)集、事務(wù)、并發(fā)等容器級(jí)事務(wù),這使得JPA超越了簡(jiǎn)單持久化框架的局限,在企業(yè)應(yīng)用發(fā)揮更大的作用。 簡(jiǎn)單易用,集成方便JPA的主要目標(biāo)之一就是提供更加簡(jiǎn)單的編程模型:在 JPA框架下創(chuàng)建實(shí)體和創(chuàng)建 Java類一樣簡(jiǎn)單,沒有任何的約束和限制,只需要使用 javax.persistence.Entity 進(jìn)行注釋;JPA的框架和接口也都非常簡(jiǎn)單,沒有太多特別的規(guī)則和設(shè)計(jì)模式的要求,開發(fā)者可以很容易的掌握。JPA基于非侵入式原則設(shè)計(jì),因此可以很容易的和其它框架或者容器集成。 可媲美JDBC的查詢能力JPA定義了獨(dú)特的 JPQL(Java Persistence Query Language),JPQL是 EJB QL的一種擴(kuò)展,它是針對(duì)實(shí)體的一種查詢語言,操作對(duì)象是實(shí)體,而不是關(guān)系數(shù)據(jù)庫的表,而且能夠支持批量更新和修改、JOIN、GROUP BY、HAVING 等通常只有 SQL才能夠提供的高級(jí)查詢特性,甚至還能夠支持子查詢。 支持面向?qū)ο蟮母呒?jí)特性JPA中能夠支持面向?qū)ο蟮母呒?jí)特性,比如類之間的繼承、多態(tài)和類之間的復(fù)雜關(guān)系,這樣的支持能夠讓開發(fā)者最大限度的使用面向?qū)ο蟮哪P驮O(shè)計(jì)企業(yè)應(yīng)用,而不需要自行處理這些特性在關(guān)系數(shù)據(jù)庫的持久化。支持內(nèi)容:JDBCORMJDOEJB 3(JPA)Java對(duì)象NoYesYesYes高級(jí)OO原理NoYesYesYes事務(wù)完整性YesYesYesYes并發(fā)YesYesYesYes大數(shù)據(jù)集YesYesYesYes現(xiàn)有 SchemaYesYesYesYes關(guān)系型和非關(guān)系型數(shù)據(jù)存儲(chǔ)NoNoYesNo查詢YesYesYesYes嚴(yán)格的標(biāo)準(zhǔn)/可移植NoNoYesYes簡(jiǎn)單易用YesYesYesYes表1持久化技術(shù)的優(yōu)缺點(diǎn)2. JPA體系架構(gòu)JPA中定義一套類和接口用于實(shí)現(xiàn)持久化管理和對(duì)象/關(guān)系的映射,下面這張圖中顯示了 JPA的主要組件以及它們之間的相互關(guān)系。圖1 JPA主要組件和相互關(guān)系 EntityManagerFactory EntityManagerFactory 是 EntityManager 的工廠類,負(fù)責(zé)創(chuàng)建 EntityManager 對(duì)象。 EntityManager EntityManager 是 JPA應(yīng)用中使用的基本對(duì)象,通過它提供的相應(yīng)方法可以管理持久化對(duì)象,也可以新建或者刪除持久化對(duì)象。EntityManager還負(fù)責(zé)創(chuàng)建Query實(shí)例。在容器外使用時(shí),EntityManagerFactory和EntityManager之間是一對(duì)一的關(guān)系。 Entity EntityTransaction提供Entity操作時(shí)需要的事務(wù)管理,和 EntityManager 是一對(duì)一的關(guān)系。在查詢操作時(shí)不需要使用 EntityTransaction,而在對(duì)象持久化、狀態(tài)更新、對(duì)象刪除等情況下則必須使用顯式的使用 EntityTransaction 的相關(guān)方法管理事務(wù)。 Query Query是查詢實(shí)體的接口,Query對(duì)象可以從 EntityManager 中獲得。根據(jù) EJB 3.0規(guī)范中的描述,Query接口需要同時(shí)支持JPQL和原生態(tài)SQL兩種語法。 Persistence Persistence是一個(gè)工具類,負(fù)責(zé)根據(jù)配置文件提供的參數(shù)創(chuàng)建EntityManagerFactory對(duì)象。 下面的代碼演示了如何通過 JPA提供的接口和 JPQL查詢語言完成實(shí)體查詢和更新的例子,例子中的代碼假定運(yùn)行在非 Java EE環(huán)境中。 清單1在非Java EE環(huán)境使用JPA接口的例子EntityManagerFactory factory = Persistence.createEntityManagerFactory (“mysql”); /從 EntityManagerFactory實(shí)例 factory中獲取 EntityManagerEntityManager em = factory.createEntityManager(PersistenceContextType.EXTENDED); /實(shí)體的更新需要在事務(wù)中運(yùn)行EntityTransaction tx = em.getTransaction ();tx.begin (); /查找所有公司中的女性雇員Query query = em.createQuery (select e from Employee e where e.sex = femail);List results = query.getResultList (); /給所有女性雇員增加半天假期for (Object res : results) Employee emp = (Employee) res; emp.setHoliday (emp.getHoliday () +0.5); /提交事務(wù)(持久化所有更新)mit ();em.close ();factory.close (); 下面的代碼顯示了在 EJB容器中開發(fā) JPA應(yīng)用時(shí)的接口使用情況,由于容器中的 EntityManager 是注入的,事務(wù)也是聲明式的,因此在容器中完成上面的業(yè)務(wù)邏輯要簡(jiǎn)單得多。 清單2在容器中運(yùn)行的JPA例子/*在容器中運(yùn)行JPA應(yīng)用時(shí),EntityManager接口的實(shí)例”em”*是通過Resource注釋注入的。事務(wù)也通常是聲明式的。*/查找所有公司中的女性雇員Query query = em.createQuery (select e from Employee e where e.sex = femail);List results = query.getResultList (); /給所有女性雇員增加半天假期for (Object res : results) Employee emp = (Employee) res; emp.setHoliday (emp.getHoliday () +0.5); 3. Entity BeanEJB3 Entity可以是很簡(jiǎn)單的java bean,只要批注了Entity或者在xml配置中作了說明,就被做一個(gè)可持久化的Entity處理。 但還是需要遵行一定的規(guī)則: Entity類必須要有一個(gè)無參數(shù)的public或者protected的Constructor。 如果在應(yīng)用中需要將該Entity類分離出來在分布式環(huán)境中作為參數(shù)傳遞,該Entity Class需要實(shí)現(xiàn)java.io.Serialzable接口。 Entity類不可以是final,也不可有final的方法。 abstract類和Concrete實(shí)體類都可以作為Entity類。 Entity類中的屬性變量不可以是public。Entity類的屬性必須通過getter/setter或者其他的商業(yè)方法獲得。3.1定義對(duì)Entity中屬性變量的訪問在絕大部分的商業(yè)應(yīng)用,開發(fā)人員都可以忽略這部分無需關(guān)心。但如果你需要編寫復(fù)雜的Entity類的話,你需要了解這個(gè)部分。復(fù)雜的Entity類是指在Entity類的getter/setter和商業(yè)方法中包含比較復(fù)雜的業(yè)務(wù)邏輯而不是僅僅返回/符值某個(gè)屬性。在大部分的情況下,我們都建議使Entity類中setter/getter中的邏輯盡可能簡(jiǎn)單,除了必要的校驗(yàn)符值外,不要包含復(fù)雜的業(yè)務(wù)邏輯,例如對(duì)關(guān)聯(lián)的其他Entity類進(jìn)行操作。但有些情況下,我們還是需要在Entity類的setter/getter方法中包含商業(yè)邏輯。這時(shí)候,采用何種屬性訪問方式就可能會(huì)影響代碼的性能甚至是邏輯正確產(chǎn)生影響。EJB3持久化規(guī)范中,在默認(rèn)情況下所有的屬性都會(huì)自動(dòng)的被持久化,除非屬性變量用Transient元數(shù)據(jù)進(jìn)行了標(biāo)注。針對(duì)可持久化屬性定義了兩種屬性訪問方式(access): FIELD和PROPERTY。 如果采用access=FIELD, EJB3 Persistence運(yùn)行環(huán)境直接訪問對(duì)象的屬性變量,而不是通過getter。這種訪問方式也不要求每個(gè)屬性必須有g(shù)etter/setter。如果需要在getter中包含商業(yè)邏輯,應(yīng)該采用access=FIELD的方式。 如果采用access=PROPERTY, EJB3 Persistence運(yùn)行環(huán)境將通過Entity類上的getter來訪問對(duì)象的屬性變量,這就要求每個(gè)屬性變量要有g(shù)etter/setter方法。在EJB3中,默認(rèn)的屬性訪問方式是PROPERTY。access=PROPERTY時(shí)getter/setter的邏輯應(yīng)該盡量簡(jiǎn)單。 規(guī)范中access方式還有多一層含義。就是采用access=FIELD時(shí),元數(shù)據(jù)應(yīng)該批注在屬性上。 Id(generate=GeneratorType.NONE) private int id; private String foo; /* * The entity class must have a no-arg constructor. */ public HelloEntityBean() public int getId() return id; 采用access=PROPERTY(默認(rèn)方式)時(shí),元數(shù)據(jù)應(yīng)該批注在對(duì)應(yīng)屬性變量的getter上。 private int id;private String foo; /* * The entity class must have a no-arg constructor.*/public HelloEntityBean() Id(generate=GeneratorType.NONE)public int getId() return id; Entity類中的屬性變量可以是以下數(shù)據(jù)類型: 原始數(shù)據(jù)類型和他們的對(duì)象類型 java.lang.String java.math.BigInteger java.math.BigDecimal java.util.Date java.util.Calendar java.sql.Date java.sql.Time java.sql.Timestamp byte Byte char Character enums Entity類 嵌入實(shí)體類(embeddable classes)還可以是以下集合類型: java.util.Collection和它的實(shí)體類 java.util.Set和它的實(shí)體類 java.util.List和它的實(shí)體類 java.util.Map和它的實(shí)體類 3.2主鍵和實(shí)體標(biāo)識(shí)(Primary Key and Entity Identity)每個(gè)Entity類都必須有一個(gè)主鍵。在EJB3中定義了兩種主鍵:鍵單主鍵和復(fù)合主鍵。 簡(jiǎn)單主鍵必須對(duì)應(yīng)Entity中的一個(gè)屬性變量(Instance Variable),而該屬性對(duì)應(yīng)數(shù)據(jù)庫表中的一列。使用簡(jiǎn)單主鍵,我們只需要用Id元數(shù)據(jù)對(duì)一個(gè)屬性變量或者她的getter方法進(jìn)行批注。當(dāng)我們需要使用一個(gè)或多個(gè)屬性變量(表中的一列或多列)聯(lián)合起來作為主鍵,我們需要使用復(fù)合主鍵。復(fù)合主鍵要求我們編寫一個(gè)復(fù)合主鍵類( Composite Primary Key Class )。復(fù)合主鍵類需要符合以下一些要求: 復(fù)合主鍵類必須是public和具備一個(gè)沒有參數(shù)的constructor 復(fù)合主鍵類的每個(gè)屬性變量必須有g(shù)etter/setter,如果沒有,每個(gè)屬性變量則必須是public或者protected 復(fù)合主鍵類必須實(shí)現(xiàn)java.io.serializable 復(fù)合主鍵類必須實(shí)現(xiàn)equals()和hashcode()方法 復(fù)合主鍵類中的主鍵屬性變量的名字必須和對(duì)應(yīng)的Entity中主鍵屬性變量的名字相同 一旦主鍵值設(shè)定后,不要修改主鍵屬性變量的值 復(fù)合主鍵的例子。Entity類Person,它的主鍵屬性變量是firstName和lastName。 Id private String firstName; Id private String lastName; public Person() Person的復(fù)合主鍵類: public class PersonPK implements java.io.Serializable private String firstName; private String lastName; public PersonPK() public String getFirstName() return firstName; public void setFirstName(String firstName) this.firstName = firstName; public String getLastName() return lastName; public void setLastName(String lastName) this.lastName = lastName; 4. EntityManager對(duì)Entity進(jìn)行操作的API都設(shè)計(jì)在javax.persistence.EntityManager接口上。EntityManager,顧名思義是管理所有EJB 3運(yùn)行環(huán)境中的所有Entity。 EntityManager根據(jù)運(yùn)行的環(huán)境不同分為容器管理的EntityManager和應(yīng)用管理的EntityManager。 4.1配置和獲得EntityManager在J2SE環(huán)境中,EJB3定義了一個(gè)javax.persistence.Persistence類用于啟動(dòng)EJB3運(yùn)行環(huán)境。要獲得EntityManager,首先需要通過javax.persistence.Persistence獲得EntityManagerFactory,然后調(diào)用EntityManagerFactory.createEntityManager()方法獲得。 /獲得默認(rèn)當(dāng)前的EntityManagerFactory final EntityManagerFactory emf = Persistence.createEntityManagerFactory(); final EntityManager entityManager = emf.createEntityManager(); 當(dāng)調(diào)用Persistence.createEntityManagerFactory()的時(shí)候,Persistence會(huì)做以下的步驟: 搜索當(dāng)前jar包的META-INFO/persistence.xml配置文件 如果沒有在META-INFO下找到persistence.xml,搜索當(dāng)前線程的ContextClassLoader中的persistence.xml 根據(jù)獲得的persistence.xml初始化EntityManagerFactory4.2 Entity的生命周期和狀態(tài)在EJB3中定義了四種Entity的狀態(tài): 新實(shí)體(new)。Entity由應(yīng)用產(chǎn)生,和EJB3 Persistence運(yùn)行環(huán)境沒有聯(lián)系,也沒有唯一的標(biāo)示符(Identity)。 持久化實(shí)體(managed)。新實(shí)體和EJB3 Persistence運(yùn)行環(huán)境產(chǎn)生關(guān)聯(lián)(通過persist(), merge()等方法),在EJB3 Persistence運(yùn)行環(huán)境中存在和被管理,標(biāo)志是在EJB3 Persistence運(yùn)行環(huán)境中有一個(gè)唯一的標(biāo)示(Identity)。 分離的實(shí)體(detached)。Entity有唯一標(biāo)示符,但它的標(biāo)示符不被EJB3 Persistence運(yùn)行環(huán)境管理,同樣的該Entity也不被EJB3 Persistence運(yùn)行環(huán)境管理。 刪除的實(shí)體(removed)。Entity被remove()方法刪除,對(duì)應(yīng)的紀(jì)錄將會(huì)在當(dāng)前事務(wù)提交的時(shí)候從數(shù)據(jù)庫中刪除。 圖2 狀態(tài)的轉(zhuǎn)化4.3持久化Entity(Persist) final EntityManagerFactory emf = Persistence.createEntityManagerFactory(); final EntityManager entityManager = emf.createEntityManager(); final HelloEntityBean hello = new HelloEntityBean( 1, foo ); EntityTransaction trans = entityManager.getTransaction(); trans.begin(); /持久化hello,在此操作之前hello的狀態(tài)為new entityManager.persist( hello ); /這時(shí)hello的狀態(tài)變?yōu)閙anaged mit(); entityManager.close(); /這時(shí)hellow的狀態(tài)變?yōu)閐etached. 當(dāng)保存一個(gè)Entity時(shí),以該對(duì)象為根對(duì)象的整個(gè)對(duì)象圖都會(huì)自動(dòng)的被保存。但在EJB3中,我們?nèi)匀豢梢酝ㄟ^關(guān)系元數(shù)據(jù)(比如OneToOne,OneToMany)的cascade屬性來精確定義保存的級(jí)聯(lián)行為。 下面我們來看看不同的cascade屬性的區(qū)別。 不配置cascade的情況下,EJB3 Persistence運(yùn)行環(huán)境默認(rèn)不會(huì)采用Persistence by reachability。 public class Father Id int id String name; / OneToOne沒有配置cascade屬性,因此默認(rèn)不會(huì)使用Persistence by reachablity OneToOne Son mySon public Father( int id, String name, Son mySon ) this.id = id; = name; this.mySon = mySon; 現(xiàn)在來保存一個(gè)Father和Son。 final EntityManager manager = emf.createEntityManager(); manager.getTransaction().begin; Son mySon = new Son(); Father = new Father( 1, father mySon ); /保存Father manager.persist( father ); /由于OneToOne關(guān)系中沒有配置casacade屬性,father關(guān)聯(lián)的mySon不會(huì)被自動(dòng)保存,需要分別保存 manager.persist( mySon ); manager.getTransaction().commit(); manager.close(); 現(xiàn)在我們配置casacde=CascadeType.ALL public class Father Id int id String name; / OneToOne配置cascade=CascadeType.ALL,配置cascade=CascadeType.PERSIT也對(duì)persist操作也可以獲得同樣的效果。 / CascadeType.ALL包含CascadeType.PERSIST。 OneToOne(cascade=CascadeType.ALL) Son mySon public Father( int id, String name, Son mySon ) this.id = id; this.mySon = mySon; = name; 在代碼中同樣持久化Father和mySon。 final EntityManager manager = emf.createEntityManager(); manager.getTransaction().begin; Son mySon = new Son(); Father = new Father( 1, mySon ); /保存Father。由于OneToOne關(guān)系中配置casacade=CascadeType.ALL屬性,關(guān)聯(lián)的mySon會(huì)自動(dòng)地被持久化 manager.persist( father ); manager.getTransaction().commit(); manager.close(); 建議在應(yīng)用中盡可能使用cascade=CascadeType.ALL來減少持久化操作的復(fù)雜性和代碼量,特別是在有復(fù)雜對(duì)象關(guān)系圖的時(shí)候。 4.4獲取Entity如果知道Entity的唯一標(biāo)示符,我們可以用find()方法來獲得Entity。 Father father = manager.find( Father.class, new Integer( 1 ) ); /由于JDK1.5支持自動(dòng)轉(zhuǎn)型,也可以如下使用 Father father = manager.find( Father.class, 1 ); /* *或者,可以用Entity名字作為查找。但無法利用JDK 1.5的自動(dòng)轉(zhuǎn)型功能, * 需要使用對(duì)象作為查找主鍵,并需要對(duì)獲得Entity進(jìn)行轉(zhuǎn)型 */ Father father = (Father)manager.find( com.redsoft.samples.Father, new Integer( 1 ) ); 4.5更新Entity對(duì)Entity的更新必須在事物內(nèi)完成。和persist中一樣,關(guān)系元數(shù)據(jù)的cascade屬性對(duì)是否集聯(lián)刪除有影響。 transaction.begin(); Father father = manager.find( Father.class, 1 ); /更新原始數(shù)據(jù)類型 father.setName( newName ); /更新對(duì)象引用 Son newSon = new Son(); father.setSon( newSon ); /提交事務(wù),剛才的更新同步到數(shù)據(jù)庫 mit(); 4.6刪除Entity對(duì)Entity的刪除必須在事物內(nèi)完成。 transaction.begin(); Father father = manager.find( Father.class, 1 ); /如果father/son的OneToOne的cascade=CascadeType.ALL,在刪除father時(shí)候,也會(huì)把son刪除。 /把cascade屬性設(shè)為cascade=CascadeType.REMOVE有同樣的效果。 manager.remove( father ); /提交事務(wù),剛才的更新同步到數(shù)據(jù)庫 mit(); 4.7脫離/附合(Detach/Merge)在三層或者分布式應(yīng)用中,我們很多時(shí)候需要Entity能脫離EntityManager,避免長時(shí)間保持EntityManager打開占用資源和可以在不同的JVM之間傳遞Entity。在脫離EJB3 Persistence Runtime(EntityManager)的管理后,我們?nèi)匀豢梢宰x取或者修改Entity中的內(nèi)容。而在稍后的時(shí)間,我們又可以將Entity重新和原有或者新的EntityManager附合,如果附合前Entity被改動(dòng)過,更改的數(shù)據(jù)可以自動(dòng)的被發(fā)現(xiàn)并和數(shù)據(jù)庫同步。 EntityManager entityManager = emf.createEntityManager(); /這時(shí)Father還是被EntityManager管理的 Father father = manager.find( Father.class, 1 ); /當(dāng)entityManger關(guān)閉的時(shí)候,當(dāng)前被entityManager管理的Entity都會(huì)自動(dòng)的脫離EntityManager,狀態(tài)轉(zhuǎn)變?yōu)閐etached entityManager.close(); /脫離EntityManager后,我們?nèi)匀豢梢孕薷腇ather的屬性 father.setName( newName ); /在稍后的,我們可以將father重新附和到一個(gè)新的或者原來的EntityManager中 EntityManager newEntityManager = emf.createEntityManager(); /附合( merge )需要在事務(wù)中進(jìn)行 newEntityManager.getTransaction().begin(); newEntityManager.merge( father ); / commit后father中的被修改的內(nèi)容會(huì)同步到數(shù)據(jù)庫。 newEntityManager.getTransaction().commit(); 5. JPA QueryJPA的查詢語言(JP)是一種和SQL非常類似的中間性和對(duì)象化查詢語言。它可以被編譯成不同的底層數(shù)據(jù)庫能接受的SQL,從而屏蔽不同數(shù)據(jù)庫的差異,確保用JPQL查詢語言編寫的代碼可在不同的數(shù)據(jù)庫上運(yùn)行。比起EJB 2.1的查詢語言,EJB3可以運(yùn)行期構(gòu)造,支持多態(tài),遠(yuǎn)遠(yuǎn)比EJB 2.1的查詢更靈活和功能強(qiáng)大。在程序中使用JPQL可以使用大寫(SELECT)或者小寫(select),但不要大小寫(比如:Select)混合使用。 5.1 Query接口javax.persistence.Query是EJB3查詢操作的接口。進(jìn)行查詢,首先要通過EntityManager獲得Query對(duì)象。 public Query createQuery(String ejbqlString); 下面我們做一個(gè)最簡(jiǎn)單的查詢,查詢所有的com.redsoft.samples.Order類。 final Query query = entityManager.createQuery( select o from Order o); final List result = query.getResultList(); final Iterator iterator = result.iterator(); while( iterator.hasNext() ) /處理Order 注意from Order。Order在EJB3查詢中稱為com.redsoft.samples.Order類的abstract schema Type。查詢Entity在JPQL中都是針對(duì)Entity的Abstract Schema Type進(jìn)行查詢。 在同一個(gè)EntityManagerFactory中,不允許同時(shí)有兩個(gè)Abstract Schema Type相同的Entity類。比如不允許同時(shí)有com.redsoft.samples.Order和com.redsoft.foo.Order。 Query返回一個(gè)List的集合結(jié)果,我們可以用Iterator或者List.get( int )的方法來獲得每個(gè)符合條件的Entity。 如果查詢結(jié)果結(jié)合中包含所有符合條件的Entity, EJB3 Persistence運(yùn)行環(huán)境默認(rèn)會(huì)自動(dòng)緩存每次查詢的結(jié)果。這樣下次同樣的查詢操作就無需訪問數(shù)據(jù)庫,而直接從緩存中返回結(jié)果集合。但如果在下次查詢操作之前,有針對(duì)被緩存的Entity類進(jìn)行update/insert/delete操作,則緩存的結(jié)果集合會(huì)自動(dòng)被清空,這樣下次查詢就會(huì)從數(shù)據(jù)庫獲得數(shù)據(jù), 確保查詢總是獲得正確的結(jié)果,避免緩存臟數(shù)據(jù)。有時(shí)候查詢會(huì)返回海量的數(shù)據(jù)。注意關(guān)閉對(duì)集合結(jié)果的緩存。 /假設(shè)返回的結(jié)果數(shù)量巨大 final Query query = entityManager.createQuery( select o from Order o); /關(guān)閉對(duì)查詢結(jié)果的緩存 query.setHint( Constants.QUERY_RESULT_CACHE, false); final List result = query.getResultList(); final Iterator iterator = result.iterator(); /這里我們可以處理海量的數(shù)據(jù) while( iterator.hasNext() ) /處理Order 5.2簡(jiǎn)單查詢下面是一個(gè)簡(jiǎn)單查詢的例子,可以看到和SQL的使用方法很類似。 final Query query = entityManager.createQuery( select o from Order o where o.id = 1); final Query query = entityManager.createQuery( select o from Order o where o.id = 1 and o.confirm = true ); final Query query = entityManager.createQuery( select o from Order o where o.id = 1 or o.customer = foo ); / address是Order類上的一個(gè)對(duì)象變量屬性,Address有一個(gè)streetNumber的屬性final Query query = entityManager.createQuery( select o from Order o where o.address.streetNumber = 123 ); 注意條件語句中查詢的是Entity的屬性,屬性的名字需要和Entity中的屬性變量名字一致。 5.3使用參數(shù)查詢參數(shù)查詢也和SQL中的參數(shù)查詢類似。JPQL支持兩種方式的參數(shù)定義方式:命名參數(shù)和位置參數(shù)。在同一個(gè)查詢中只允許使用一種參數(shù)定義方式。 final Query query = entityManager.createQuery( select o from Order o where o.id = :myId); /設(shè)置查詢中的參數(shù) query.setParameter( myId, 2 ); /可以使用多個(gè)參數(shù) final Query query = entityManager.createQuery( select o from Order o where o.id = :myId and o.customer = :customerName ); /設(shè)置查詢中的參數(shù) query.setParameter( myId, 2 ); query.setParameter( customerName, foo ); final Query query = entityManager.createQuery( select o from Order o where o.id = ?1); /設(shè)置查詢中的參數(shù) query.setParameter( 1, 2 );/ 1表示第一個(gè)參數(shù),2是參數(shù)的值 /或者 final Query query = entityManager.createQuery( select o from Order o where o.id = ?1).setParameter( 1, 2 ); /可以使用多個(gè)參數(shù) final Query query = entityManager.createQuery( select o from Order o where o.id = ?1 and o.customer = ?2 ); /設(shè)置查詢中的參數(shù) query.setParameter( 1, 2 ); query.setParameter( 2, foo ); 如果在未來需要在不同的EJB3運(yùn)行環(huán)境中運(yùn)行,請(qǐng)使用位置參數(shù),保證應(yīng)用是可移植的。 5.4排序(order by)下面是一個(gè)簡(jiǎn)單查詢的例子,可以看到和SQL的使用方法很類似。ASC和DESC分別為升序和降序,如果不顯式注明,JPQL中默認(rèn)為asc升序。 /不注明的話,默認(rèn)為asc為升序, final Query query = entityManager.createQuery( select o from Order o order by o.id); final Query query = entityManager.createQuery( select o from Order o order by o.address.streetNumber desc);/ desc為降序 final Query query = entityManager.createQuery( select o from Order o order by o.id

溫馨提示

  • 1. 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請(qǐng)下載最新的WinRAR軟件解壓。
  • 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請(qǐng)聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶所有。
  • 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁內(nèi)容里面會(huì)有圖紙預(yù)覽,若沒有圖紙預(yù)覽就沒有圖紙。
  • 4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
  • 5. 人人文庫網(wǎng)僅提供信息存儲(chǔ)空間,僅對(duì)用戶上傳內(nèi)容的表現(xiàn)方式做保護(hù)處理,對(duì)用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對(duì)任何下載內(nèi)容負(fù)責(zé)。
  • 6. 下載文件中如有侵權(quán)或不適當(dāng)內(nèi)容,請(qǐng)與我們聯(lián)系,我們立即糾正。
  • 7. 本站不保證下載資源的準(zhǔn)確性、安全性和完整性, 同時(shí)也不承擔(dān)用戶因使用這些下載資源對(duì)自己和他人造成任何形式的傷害或損失。

評(píng)論

0/150

提交評(píng)論