自拍偷在线精品自拍偷,亚洲欧美中文日韩v在线观看不卡

Java EE 6引入的JPA 2.0四大新特性詳解

原創(chuàng)
開發(fā) 后端
JPA 2.0是在Java EE 6當(dāng)中新引入的Java持久化API。JPA 2.0帶來了許多新特性和增強(qiáng),其中包括對象/關(guān)系映射增強(qiáng),Java持久化查詢語言增強(qiáng),一種新的基于標(biāo)準(zhǔn)的查詢API,以及對悲觀鎖的支持。

【51CTO精選譯文】Java EE 5平臺引入了Java持久化API(Java Persistence API,JPA),它為Java EE和Java SE應(yīng)用程序提供了一個(gè)基于POJO的持久化模塊。JPA處理關(guān)系數(shù)據(jù)與Java對象之間的映射,它使對象/關(guān)系(O/R)映射標(biāo)準(zhǔn)化,JPA已經(jīng)被廣泛采用,已經(jīng)成為事實(shí)上的O/R持久化企業(yè)標(biāo)準(zhǔn)。

Java EE 6帶來了JPA的最新版本 — JSR 317:Java持久化2.0,JPA 2.0帶來了許多新特性和增強(qiáng),包括:

1、對象/關(guān)系映射增強(qiáng);

2、Java持久化查詢語言增強(qiáng);

3、一種新的基于標(biāo)準(zhǔn)的查詢API;

4、支持悲觀鎖定。

對象/關(guān)系映射增強(qiáng)

JPA 1.0支持集合的映射,但這些集合只能包含實(shí)體,JPA 2.0增加了集合映射的基礎(chǔ)數(shù)據(jù)類型,如String和Integer,以及嵌入式對象的集合。JPA中的嵌入式對象是一個(gè)不能存在于它自身的對象,而是作為父對象的一部分存在,即它的數(shù)據(jù)不是存在于它自己的表中,而是嵌入在父對象的表中。

JPA 2.0增加了兩個(gè)支持新的集合映射的注解:@ElementCollection 和 @CollectionTable。使用@ElementCollection注解指定集合的嵌入式對象,這些集合是獨(dú)立存儲在集合表中的,使用@CollectionTable注解指定集合表的詳細(xì)信息,如它包含的列。

下面是一個(gè)嵌入式類,表示了車輛的訪問服務(wù),它存儲了訪問的日期,描述和費(fèi)用,此外,車輛可以配備一或多個(gè)可選功能,每個(gè)功能是FeatureType類型的一個(gè)枚舉值。

  1. public enum FeatureType { AC, CRUISE, PWR, BLUETOOTH, TV, ... }  
  2.  
  3.    @Embeddable 
  4.    public class ServiceVisit {  
  5.        @Temporal(DATE)  
  6.        @Column(name="SVC_DATE")  
  7.        Date serviceDate;  
  8.  
  9.        String workDesc;  
  10.        int cost;  
  11.    }  

枚舉值和嵌入式對象可以在一個(gè)表示車輛服務(wù)歷史的實(shí)體中使用,如:

  1. @Entity 
  2.    public class Vehicle {  
  3.  
  4.        @Id int vin;  
  5.  
  6.        @ElementCollection 
  7.        @CollectionTable(name="VEH_OPTNS")  
  8.   .    @Column(name="FEAT")  
  9.        Set<FeatureType> optionalFeatures;  
  10.  
  11.        @ElementCollection 
  12.        @CollectionTable(name="VEH_SVC")  
  13.        @OrderBy("serviceDate")  
  14.        List<ServiceVisit> serviceHistory;  
  15.        ...  
  16.    }  

#t#Vehicle實(shí)體中的第一對注解@ElementCollection 和 @CollectionTable指定FeatureType值存儲在VEH_OPTNS集合表中,第二對注解@ElementCollection 和 @CollectionTable指定ServiceVisit嵌入式對象存儲在VEH_SVC集合表中。

雖然在例子中沒有顯示,@ElementCollection注解有兩個(gè)屬性:targetClass 和 fetch。targetClass屬性指定基礎(chǔ)類或嵌入式類的類名,如果字段或?qū)傩允鞘褂梅盒投x的,那這兩個(gè)屬性是可選的,上面這個(gè)例子就是這樣。Fetch屬性是可選的,它指定集合是延后檢索還是立即檢索,使用javax.persistence.FetchType常量,值分別用LAZY和EAGER,默認(rèn)情況下,集合是延后匹配的。

JPA 2.0中還有其它許多關(guān)于對象/關(guān)系映射的增強(qiáng),例如,JPA 2.0支持嵌套式嵌入,關(guān)系嵌入和有序列表,也增加了新的注解增強(qiáng)映射功能,通過@Access注解更靈活地支持特定的訪問類型,更多用于實(shí)體關(guān)系的映射選項(xiàng),如對單向一對多關(guān)系的外鍵映射支持,通過@MapsId注解支持派生身份,支持孤體刪除。

#p#

Java持久化查詢語言增強(qiáng)

JPA 1.0定義了一個(gè)廣泛的Java持久化查詢語言(非正式簡稱為JPQL。有關(guān)JPQL查詢的缺陷,可參考51CTO之前發(fā)布的這篇文章),使用它你可以查詢實(shí)體和它們的持久化狀態(tài)。JPA 2.0對JPQL做了大量改進(jìn),如現(xiàn)在可以在查詢中使用case表達(dá)式。在下面的查詢中,如果雇員的評分為1,則通過乘以1.1對雇員的薪水進(jìn)行了增長,如果評分為2,則乘以1.05,其它評分則乘以1.01。

  1. UPDATE Employee e  
  2.    SET e.salary =  
  3.       CASE WHEN e.rating = 1 THEN e.salary * 1.1  
  4.            WHEN e.rating = 2 THEN e.salary * 1.05  
  5.            ELSE e.salary * 1.01  
  6.       END 

JPA 2.0也為JPQL增加了大量新的運(yùn)算符,如NULLIF和COALESCE,當(dāng)數(shù)據(jù)庫使用其它非空數(shù)據(jù)解碼時(shí),NULLIF運(yùn)算符是非常有用的,使用NULLIF,你可以在查詢中將這些值轉(zhuǎn)換為空值,如果參數(shù)等于NULLIF,NULLIF會(huì)返回空值,否則返回第一個(gè)參數(shù)的值。

假設(shè)薪水?dāng)?shù)據(jù)保存在employee表中,數(shù)據(jù)類型為整數(shù),卻掉的薪水解碼為-9999,下面的查詢返回薪水的平均值,為了正確地忽略卻掉的薪水,查詢使用NULLIF將-9999轉(zhuǎn)換為空值。

  1. SELECT AVG(NULLIF(e.salary, -99999))  
  2.    FROM Employee e  

COALESCE運(yùn)算符接收一串參數(shù),從列表中返回第一個(gè)非空值,相當(dāng)于下面的case表達(dá)式:

  1. CASE WHEN value1 IS NOT NULL THEN value1  
  2.         WHEN value2 IS NOT NULL THEN value2  
  3.         WHEN value3 IS NOT NULL THEN value3  
  4.         ...  
  5.         ELSE NULL 
  6.    END 

假設(shè)employee表包括一個(gè)辦公電話號碼和家庭電話號碼列,無電話號碼的列使用空值表示。下面的查詢返回每個(gè)雇員的姓名和電話號碼,COALESCE運(yùn)算符指定查詢返回辦公電話號碼,但如果為空,則返回家庭電話號碼,如果兩者都為空,則返回一個(gè)空值。

  1. SELECT NameCOALESCE(e.work_phone, e.home_phone) phone  
  2.    FROM Employee e  

#t#JPA 2.0向JPQL增加的其它運(yùn)算符是INDEX,TYPE,KEY,VALUE和ENTRY。INDEX運(yùn)算符指定查詢時(shí)的排序順序,TYPE運(yùn)算符選擇一個(gè)實(shí)體的類型,將查詢限制到一或多個(gè)實(shí)體類型,KEY,VALUE和ENTRY運(yùn)算符是JPA 2.0中的泛化映射功能的一部分。使用KEY運(yùn)算符提取映射鍵,VALUE運(yùn)算符提取映射值,ENTRY運(yùn)算符選擇一個(gè)映射實(shí)體。

此外,JPA 2.0增加了選擇列表、以及集合值參數(shù)和非多態(tài)查詢中運(yùn)算符的支持。

#p#

標(biāo)準(zhǔn)的API

JPA 2.0中引入的另一個(gè)重要特性是標(biāo)準(zhǔn)的API,利用這個(gè)API可以動(dòng)態(tài)地構(gòu)建基于對象的查詢,本質(zhì)上,這個(gè)標(biāo)準(zhǔn)API等價(jià)于面向?qū)ο蟮腏PQL,使用它,你可以使用基于對象的方法創(chuàng)建查詢,不再需要JPQL使用的字符串操作。

標(biāo)準(zhǔn)API是基于元模型的,元模型是一個(gè)提供了架構(gòu)級關(guān)于持久化單元托管類的元數(shù)據(jù)的抽象模型, 元模型讓你構(gòu)建強(qiáng)類型的查詢,它也允許你瀏覽持久化單元的邏輯結(jié)構(gòu)。

通常,一個(gè)注解處理器使用元模型生成靜態(tài)元模型類,這些類提供持久化狀態(tài)和持久化單元托管類的關(guān)系,但你可以對靜態(tài)元模型類編碼。下面是一個(gè)實(shí)體實(shí)例:

  1. @Entity public class Employee {  
  2.      @Id Long Id;  
  3.      String firstName;  
  4.      String lastName;  
  5.      Department dept;  
  6.    }  

下面是對應(yīng)的靜態(tài)元模型類:

  1. import javax.persistence.meta,model.SingularAttribute;  
  2.    import javax.persistence.meta,model.StaticMetamodel;  
  3.  
  4.  
  5.    @Generated("EclipseLink JPA 2.0 Canonical Model Generation" 
  6.    @StaticMetamodel(Employee.class)  
  7.    public class Employee_ {  
  8.      public static volatile SingularAttribute<Employee, Long> id;  
  9.      public static volatile SingularAttribute<Employee, String> firstName;  
  10.      public static volatile SingularAttribute<Employee, String> lastName;  
  11.      public static volatile SingularAttribute<Employee, Department> dept;  
  12.  
  13.    }  

此外,JPA 2.0元模型API允許你動(dòng)態(tài)訪問元模型,因此當(dāng)你使用標(biāo)準(zhǔn)API時(shí),既可以靜態(tài)訪問元模型類,也可以動(dòng)態(tài)訪問元模型類。標(biāo)準(zhǔn)API提供了更好的靈活性,既可以使用基于對象的方法,又可以使用基于字符串的方法導(dǎo)航元模型,這意味著你有四種使用標(biāo)準(zhǔn)API的方法:

1、靜態(tài)使用元模型類

2、靜態(tài)使用字符串

3、動(dòng)態(tài)使用元模型

4、動(dòng)態(tài)使用字符串

無論你使用哪種方法,通過構(gòu)造一個(gè)CriteriaQuery對象定義一個(gè)基于標(biāo)準(zhǔn)API的查詢時(shí),使用一個(gè)工廠對象CriteriaBuilder構(gòu)造CriteriaQuery,可以從EntityManager 或 EntityManagerFactory類中獲得CriteriaBuilder。下面的代碼構(gòu)造一個(gè)CriteriaQuery對象:

  1. EntityManager em = ... ;  
  2.    CriteriaBuilder cb = em.getCriteriaBuilder();  
  3.    CriteriaQuery<Customer> cq = cb.createQuery(Customer.class);  

注意CriteriaQuery對象是泛型類型,使用CriteriaBuilder 的createQuery方法創(chuàng)建一個(gè)CriteriaQuery,并為查詢結(jié)果指定類型。在這個(gè)例子中,createQuery 方法的Employee.class參數(shù)指定查詢結(jié)果類型是Employee。CriteriaQuery對象和創(chuàng)建它們的方法是強(qiáng)類型的。

接下來,為CriteriaQuery對象指定一個(gè)或多個(gè)查詢源,查詢源表示查詢基于的實(shí)體。你創(chuàng)建一個(gè)查詢源,然后使用AbstractQuery接口的from()方法將其添加到查詢。AbstractQuery接口是眾多接口中的一員,如CriteriaQuery,F(xiàn)rom和root,它們都定義在標(biāo)準(zhǔn)API中。CriteriaQuery接口繼承AbstractQuery接口的屬性。

from()方法的參數(shù)是實(shí)體類或EntityType實(shí)體的實(shí)例,from()方法的結(jié)果是一個(gè)Root對象,Root接口擴(kuò)展From接口,它表示某個(gè)查詢的from子句中可能出現(xiàn)的對象。

下面的代碼增加一個(gè)查詢源到CriteriaQuery對象:

  1. CriteriaBuilder cb = em.getCriteriaBuilder();  
  2.    CriteriaQuery<Employee> cq = cb.createQuery(Employee.class);  
  3.    Root<Employee> emp = cq.from(Employee.class);  

當(dāng)你向CriteriaQuery對象添加一個(gè)或多個(gè)查詢源后,你訪問元模型,然后構(gòu)造一個(gè)查詢表達(dá)式,你如何做取決于你是以靜態(tài)方式提交查詢還是以動(dòng)態(tài)方式提交查詢,以及是使用元模型還是字符串導(dǎo)航元模型。下面是一個(gè)使用元模型類靜態(tài)查詢的例子:

  1. cq.select(emp);  
  2.    cq.where(cb.equal(emp.get(Employee_.lastName), "Smith"));  
  3.    TypedQuery<Employee> query = em.createQuery(cq);  
  4.    List<Employee> rows = query.getResultList();  

CriteriaQuery接口的select() 和 where()方法指定查詢結(jié)果返回的選擇項(xiàng)目。

注意,你使用EntityManager創(chuàng)建查詢時(shí),可以在輸入中指定一個(gè)CriteriaQuery對象,它返回一個(gè)TypedQuery,它是JPA 2.0引入javax.persistence.Query接口的一個(gè)擴(kuò)展,TypedQuery接口知道它返回的類型。

在元模型術(shù)語中,Employee_是對應(yīng)于Employee實(shí)體類的規(guī)范化元模型類,一個(gè)規(guī)范化元模型類遵循JPA 2.0規(guī)范中描述的某些規(guī)則。例如,元模型類的名字來源于托管類,一般都是在托管類名字后面追加一個(gè)下劃線“_”。一個(gè)規(guī)范化元模型是一個(gè)包含靜態(tài)元模型類的元模型,這個(gè)靜態(tài)元模型對應(yīng)于實(shí)體,映射的超類,以及持久化單元中的嵌入式類。實(shí)際上,這個(gè)查詢使用了規(guī)范化元模型。下面是一個(gè)完整的查詢:

  1. EntityManager em = ... ;  
  2.    CriteriaBuilder cb = em.getCriteriaBuilder();  
  3.    CriteriaQuery<Employee> cq = cb.createQuery(Employee.class);  
  4.    Root<Employee> emp = cq.from(Employee.class);  
  5.    cq.select(emp);  
  6.    cq.where(cb.equal(emp.get(Employee_.lastName), "Smith"));  
  7.    TypedQuery<Employee> query = em.createQuery(cq);  
  8.    List<Employee> rows = query.getResultList();  

下面是使用元模型API查詢的動(dòng)態(tài)版本:

  1. EntityManager em = ... ;  
  2.    CriteriaBuilder cb = em.getCriteriaBuilder();  
  3.    CriteriaQuery<Employee> cq = cb.createQuery(Employee.class);  
  4.    Root<Employee> emp = cq.from(Employee.class);  
  5.    EntityType<Employee> emp_ = emp.getModel();  
  6.    cq.select(emp);  
  7.    cq.where(cb.equal(emp.get(emp_.getSingularAttribute("lastName", String.class)),"Smith"));  
  8.    TypedQuery<Employee> query=em.createQuery(cq);  
  9.    List<Employee> rows=query.getResultList();  

#t#使用元模型API的標(biāo)準(zhǔn)查詢提供了與使用規(guī)范化元模型相同的類型,但它比基于規(guī)范化元模型的查詢更冗長。

Root的getModel()方法返回根對應(yīng)的元模型實(shí)體,它也允許運(yùn)行時(shí)訪問在Employee實(shí)體中聲明的持久化屬性。

getSingularAttribute()方法是一個(gè)元模型API方法,它返回一個(gè)持久化的單值屬性或字段,在這個(gè)例子中,它返回值為Smith 的lastName屬性。下面是使用字符串的元數(shù)據(jù)導(dǎo)航查詢的靜態(tài)版本:

  1. EntityManager em = ... ;  
  2.    CriteriaBuilder cb = em.getCriteriaBuilder();  
  3.    CriteriaQuery<Employee> cq = cb.createQuery(Employee.class);  
  4.    Root<Employee> emp = cq.from(Employee.class);  
  5.    cq.select(emp);  
  6.    cq.where(cb.equal(emp.get("lastName"), "Smith"));  
  7.    TypedQuery query = em.createQuery(cq);  
  8.    List <Employee>rows = query.getResultList();  

這個(gè)基于字符串的方法要相對容易使用些,但卻失去了元模型具有的類型安全。

#p#

支持悲觀鎖

鎖是處理數(shù)據(jù)庫事務(wù)并發(fā)的一種技術(shù),當(dāng)兩個(gè)或更多數(shù)據(jù)庫事務(wù)并發(fā)地訪問相同數(shù)據(jù)時(shí),鎖可以保證同一時(shí)間只有一個(gè)事務(wù)可以修改數(shù)據(jù)。

鎖的方法通常有兩種:樂觀鎖和悲觀鎖。樂觀鎖認(rèn)為多個(gè)并發(fā)事務(wù)之間很少出現(xiàn)沖突,也就是說不會(huì)經(jīng)常出現(xiàn)同一時(shí)間讀取或修改相同數(shù)據(jù),在樂觀鎖中,其目標(biāo)是讓并發(fā)事務(wù)自由地同時(shí)得到處理,而不是發(fā)現(xiàn)或預(yù)防沖突。兩個(gè)事務(wù)在同一時(shí)刻可以訪問相同的數(shù)據(jù),但為了預(yù)防沖突,需要對數(shù)據(jù)執(zhí)行一次檢查,檢查自上次讀取數(shù)據(jù)以來發(fā)生的任何變化。

悲觀鎖認(rèn)為事務(wù)會(huì)經(jīng)常發(fā)生沖突,在悲觀鎖中,讀取數(shù)據(jù)的事務(wù)會(huì)鎖定數(shù)據(jù),在前面的事務(wù)提交之前,其它事務(wù)都不能修改數(shù)據(jù)。

JPA 1.0只支持樂觀鎖,你可以使用EntityManager類的lock()方法指定鎖模式的值,可以是READ或WRITE,如:

  1. EntityManager em = ... ;  
  2.    em.lock (p1, READ);  

對于READ鎖模式,JPA實(shí)體管理器在事務(wù)提交前都會(huì)鎖定實(shí)體,檢查實(shí)體的版本屬性確定實(shí)體自上次被讀取以來是否有更新,如果版本屬性被更新了,實(shí)體管理器會(huì)拋出一個(gè)OptimisticLockException異常,并回滾事務(wù)。

對于WRITE鎖模式,實(shí)體管理器執(zhí)行和READ鎖模式相同的樂觀鎖操作,但它也會(huì)更新實(shí)體的版本列。

JPA 2.0增加了6種新的鎖模式,其中兩個(gè)是樂觀鎖。JPA 2.0也允許悲觀鎖,并增加了3種悲觀鎖,第6種鎖模式是無鎖。

下面是新增的兩個(gè)樂觀鎖模式:

1、OPTIMISTIC:它和READ鎖模式相同,JPA 2.0仍然支持READ鎖模式,但明確指出在新應(yīng)用程序中推薦使用OPTIMISTIC。

2、OPTIMISTIC_FORCE_INCREMENT:它和WRITE鎖模式相同,JPA 2.0仍然支持WRITE鎖模式,但明確指出在新應(yīng)用程序中推薦使用OPTIMISTIC_FORCE_INCREMENT。

下面是新增的三個(gè)悲觀鎖模式:

1、PESSIMISTIC_READ:只要事務(wù)讀實(shí)體,實(shí)體管理器就鎖定實(shí)體,直到事務(wù)完成鎖才會(huì)解開,當(dāng)你想使用重復(fù)讀語義查詢數(shù)據(jù)時(shí)使用這種鎖模式,換句話說就是,當(dāng)你想確保數(shù)據(jù)在連續(xù)讀期間不被修改,這種鎖模式不會(huì)阻礙其它事務(wù)讀取數(shù)據(jù)。

2、PESSIMISTIC_WRITE:只要事務(wù)更新實(shí)體,實(shí)體管理器就會(huì)鎖定實(shí)體,這種鎖模式強(qiáng)制嘗試修改實(shí)體數(shù)據(jù)的事務(wù)串行化,當(dāng)多個(gè)并發(fā)更新事務(wù)出現(xiàn)更新失敗幾率較高時(shí)使用這種鎖模式。

3、PESSIMISTIC_FORCE_INCREMENT:當(dāng)事務(wù)讀實(shí)體時(shí),實(shí)體管理器就鎖定實(shí)體,當(dāng)事務(wù)結(jié)束時(shí)會(huì)增加實(shí)體的版本屬性,即使實(shí)體沒有修改。

你也可以指定新的鎖模式NONE,在這種情況下表示沒有鎖發(fā)生。

JPA 2.0也提供了多種方法為實(shí)體指定鎖模式,你可以使用EntityManager的lock() 和 find()方法指定鎖模式。此外,EntityManager.refresh()方法可以恢復(fù)實(shí)體實(shí)例的狀態(tài)。

下面的代碼顯示了使用PESSIMISTIC_WRITE鎖模式的悲觀鎖:

  1. // read  
  2.    Part p = em.find(Part.class, pId);  
  3.  
  4.    // lock and refresh before update  
  5.    em.refresh(p, PESSIMISTIC_WRITE);  
  6.    int pAmount = p.getAmount();  
  7.    p.setAmount(pAmount - uCount);  

在這個(gè)例子中,它首先讀取一些數(shù)據(jù),然后應(yīng)用PESSIMISTIC_WRITE鎖,在更新數(shù)據(jù)之前調(diào)用EntityManager.refresh()方法,當(dāng)事務(wù)更新實(shí)體時(shí),PESSIMISTIC_WRITE鎖鎖定實(shí)體,其它事務(wù)就不能更新相同的實(shí)體,直到前面的事務(wù)提交。

更多JPA 2.0的新特性

除了前面描述的增強(qiáng)和新特性外,JPA 2.0可以使用Bean驗(yàn)證自動(dòng)驗(yàn)證實(shí)體,這意味著你可以在實(shí)體上指定一個(gè)約束,例如,實(shí)體中字段的最大長度為15,當(dāng)實(shí)體持久化,更新或移除時(shí)自動(dòng)驗(yàn)證字段,你可以在persistence.xml配置文件中使用<validation-mode>元素指定自動(dòng)驗(yàn)證生效的周期。

【51CTO.com譯稿,非經(jīng)授權(quán)請勿轉(zhuǎn)載。合作站點(diǎn)轉(zhuǎn)載請注明原文譯者和出處為51CTO.com,且不得修改原文內(nèi)容。】

原文:A More Complete Java Persistence API  作者:Ed Ort

責(zé)任編輯:yangsai 來源: 51CTO.com
相關(guān)推薦

2009-12-22 09:57:36

Java EE 6RESTfulJAX-RS

2011-04-02 09:45:00

Ubuntu 11.0特性

2010-09-03 08:47:51

2010-05-25 08:34:10

C# 4.0

2009-07-03 17:40:35

JSP2.0

2010-06-09 10:48:55

F#Silverlight

2010-09-15 13:35:25

SwingHibernateStruts

2020-01-10 15:44:50

編程語言C++Java

2012-11-16 11:11:06

深度影音Linux Deepi

2010-03-26 14:37:57

Visual Stud

2010-06-03 09:09:10

Hadoop

2019-10-15 08:00:00

HTTP2HTTP前端

2010-11-19 10:36:17

RHEL 6

2020-09-21 18:44:35

MySQL

2015-10-26 09:04:21

PHP7新特性

2010-09-29 14:08:31

2009-07-07 12:30:38

JDK1.6

2009-08-28 10:47:46

Java EE容器

2011-06-22 08:38:35

Java EE

2010-01-14 09:15:07

Java EE 6Servlet 3.0異步處理
點(diǎn)贊
收藏

51CTO技術(shù)棧公眾號