結合SPRING 2.0使用JAVA PERSISTENCE API

摘要

  Java Persistence API(JPA)和Spring Framework的2.0版本已經引發開發人員普遍的興趣。本文將考察如何將Spring 2.0和JPA與BEA WebLogic Server一塊兒使用。具體來講,咱們將使用Spring和JPA對WebLogic Server的病歷示例應用程序進行更新。本文將展現Spring和JPA這個功能強大的組合如何造成基於POJO的簡化應用架構的基礎。使用的技術主要包括WebLogic Server 9.一、Spring 2.0和Kodo JPA。

簡介

  病歷示例應用程序(MedRec)是一個綜合應用程序,它演示瞭如何在WebLogic Server中使用多種技術。這些技術包括開源技術(如Spring和Struts)以及WebLogic Server所使用的技術(如Web services、JSP、消息驅動bean和JDBC)。
   本文描述在MedRec更新版本中Java Persistence API(JPA)是如何與Spring Framework配合使用的。本文的一個重要目的是向開發人員展現Spring 2.0、WebLogic Server 9.1和Kodo 4.0如何一塊兒使用。經過閱讀本文,開發人員將得到對有關使用JPA和Spring 2.0版本中新增的JPA支持的瞭解。本文還將討論在企業應用的多個層次中重用JavaBean(POJO)時可能出現的挑戰。重用是基於Spring和JPA的應用架構所帶來的重要獲益之一。
   對於不熟悉 Java Persistence API的人來講,JPA是一個指定如何將Java對象保存在數據庫中的新增簡化API。JPA正在做爲EJB 3.0( JSR 220)的一部分而被開發,由於它將取代EJB 2.x實體bean,可是它在J2EE和J2SE應用程序中都可使用。JPA的一個最重要的特性是:它是基於POJO的。JPA還使用Java 5.0註釋來簡化指定從Java對象到關係數據庫的映射的方式。BEA已經宣告創建 OpenJPA(一個很快就可用的基於Kodo的開源項目),可是您如今就能夠開始使用 Kodo 4.0的早期訪問版本。
   本文將從對Spring中的POJO和數據訪問的概述開始。接下來概述MedRec的架構,並對MedRec數據訪問層進行更詳細的描述。而後咱們將詳細考察JPA persistent類,並討論它們須要遵循的設計模式。最後,咱們將介紹Spring和Kodo JPA的XML配置,以便將全部內容聯繫起來。MedRec的完整源代碼可隨本文 下載

Spring中的POJO和數據訪問

  Spring Framework最著名的優勢多是簡化了的業務組件開發。熟悉Spring的人都知道,經過使用反向控制(IoC)和麪向方面編程(AOP),Spring容許開發人員編寫功能強大的業務組件,這些業務組件仍然是常規JavaBean或POJO (Plain Old Java Object)——正如它們一般被稱做的那樣。
   對於須要訪問數據庫的企業應用程序,Spring也提供了一個框架來簡化對封裝持久化數據訪問的數據訪問對象(DAO)的建立。Spring的POJO功能還涉及數據訪問領域,由於它們查詢和修改的數據訪問對象和域模型對象都可以是POJO。
   Spring對POJO模式的使用具備一些重要的實際優勢。首先,就業務組件而言,POJO減輕了開發人員爲實現應用程序而必須作的工做。它不只減小了代碼行,並且因爲這些代碼自己就是標準Java,因此它們更簡單。其次,使用POJO意味着應用程序調用數據訪問對象的其他代碼不依賴於特定的持久化技術。例如,若是應用程序正在使用原始JDBC或JDO,那麼使用POJO則會使轉換到使用JPA做爲持久化解決方案的行爲相對容易。
   第三個優勢涉及域模型對象自己。在MedRec中,域模型對象表明諸如病人、醫生和處方之類的實體。因爲這些類是POJO,並且不像傳統的EJB 2.x實體bean那樣依賴於特定的持久化環境,因此這些類能夠在多個應用程序代碼須要訪問域模型的層次中重用。在MedRec中,這包括JSP使用域模型對象呈現用戶界面的Web層,以及使用域模型類做爲參數並將類型返回給Web服務方法的Web服務層。

MedRec概覽

  若是但願全面概覽MedRec應用程序的架構及其使用Spring的方式,請閱讀 Spring Integration with WebLogic Server(中文版,dev2dev,2006年3月)。這篇文章很好地描述了Spring和WebLogic Server之間的常規集成。這裏咱們將簡要討論MedRec架構,以說明JPA是如何用於MedRec環境的。
   圖1展現了MedRec的總體架構。在最高層,MedRec其實是兩個獨立的J2EE應用(EAR文件):MedRec應用程序和Physician應用程序。全部的數據訪問都由MedRec部分完成,因此咱們將關注這部分。
MedRec概覽
圖1:MedRec應用程序架構
   如圖1所示,MedRec應用程序分爲幾個層:一個包含Web服務的表示層、一個服務層、一個包括數據訪問的集成層以及數據庫層。做爲集成層一部分的Spring數據訪問對象(DAO)主要由服務層的業務對象調用。DAO和服務對象都是由Spring應用程序上下文配置的Spring bean。服務對象使用Spring的聲明式事務支持來控制事務。

MedRec數據訪問

  Medical Records應用程序使用4種不一樣的DAO,每一種對應於一個須要保存的域模型類——Patient、Prescription、Record和User。DAO實現類分別被稱爲JpaPatientDAO、JpaPrescriptionDAO、JpaRecordDAO和JpaUserDAO,能夠在com.bea.medrec.dao.orm包中找到。
   讓咱們更詳細地考察Patient DAO,以便弄清楚它是如何工做的。如下是用於處理病歷應用程序中病人數據的檢索和更新的數據訪問對象接口:
public interface PatientDao {
  public Patient getById(Integer patientId) 
    throws DataAccessException;
  public List getByEmail(String email) 
    throws DataAccessException;
  public List getByLastName(String lastName) 
    throws DataAccessException;
  public List getByLastNameFirstName(String lastName,
    String firstName) throws DataAccessException;
  public List getByLastNameWild(String lastName) 
    throws DataAccessException;
  public Patient getBySsn(String ssn) 
    throws DataAccessException;
  public List getByStatus(String status) 
    throws DataAccessException;
  public Patient getByUsername(String username) 
    throws DataAccessException;
  public Patient save(Patient patient) 
    throws DataAccessException;
  
  public Patient update(Patient patient) 
    throws DataAccessException;
}
  請注意,Patient DAO接口是plain old Java interface(POJI)。它不擴展或導入任何特定於所使用的持久化技術(本例中是JPA)的Java類型。大多數Patient DAO方法執行查詢並返回病人列表或單個病人對的。最後兩個方法分別用於在數據庫中保存新病人的信息或者更新現有病人的信息。
   該接口上的每一個方法都聲明瞭一個DataAccessException,它是由Spring framework定義的運行時異常。關於DataAccessException,有兩件事須要注意。首先,它是運行時異常,因此使用數據訪問對象的應用程序代碼不須要像在JDBC和EJB 2.x實體bean的狀況下那樣使用try-catch塊包裝每次調用。第二,DataAccessException是有用的,由於它包裝底層持久化技術所使用的特定異常類,從而使應用程序的其餘部分獨立於持久化層。
   關於接口就說這麼多了。接下來,讓咱們考察一下Patient DAO的實現。如下是基類BaseDAO,MedRec中的全部數據訪問對象都對它進行擴展:
package com.bea.medrec.dao.orm;
import org.springframework.orm.jpa.support.JpaDaoSupport; 
public abstract class BaseDao extends JpaDaoSupport {
  ...
}
  在咱們的例子中,這是一個很是簡單的類,可是通常來講,它可用於在不一樣數據訪問對象實現上所共有的任何代碼。BaseDAO擴展了Spring的JpaDaoSupport類。這是必須的,由於它爲咱們的DAO實現類提供到Spring的特定於JPA的API的訪問。
   Patient DAO實現類JpaPatientDao擴展了BaseDao:
public class JpaPatientDao extends BaseDao implements PatientDao {
   public Patient getById(Integer pId) 
      throws DataAccessException {
      return getJpaTemplate().find(Patient.class, pId);
    }
    public List getByLastName(String pLastName) 
      throws DataAccessException {
        
        List patients = getJpaTemplate().find(
            "SELECT p " + 
            "FROM " + Patient.class.getSimpleName() + " p " + 
            "WHERE p.lastName LIKE ?1", pLastName);
         return (patients.isEmpty())? 
            Collections.EMPTY_LIST : patients;
    }
    ...
}
  此代碼示例還展現了兩個示範查詢方法實現。第一個是getById(),它經過病人的唯一標識字段查找病人。這是經過調用Spring的JpaTemplate上的專用find方法完成的,它將Patient類和唯一的id做爲參數,並返回具備此id的Patient對象。getByLastName()方法返回具備類似的姓的病人列表。getByLastName()使用JpaTemplate.find()的替代版本,它將後跟查詢參數的EJB QL查詢做爲參數,並返回匹配查詢的對象列表。如下是patient DAO的保存和更新方法:
public class JpaPatientDao extends BaseDao implements PatientDao {
   ...
   public Patient save(Patient pPatient) 
      throws DataAccessException {
      getJpaTemplate().persist(pPatient);
        
   return pPatient;
   }
   public Patient update(Patient pPatient) 
      throws DataAccessException {
      return getJpaTemplate().merge(pPatient);
   }
}
  在此patient DAO的保存和更新方法的實現中,save()方法用於將新病人的記錄插入數據庫,而update()則修改現有的病人記錄。每一個方法返回一個對新的或更新後的Patient對象的引用。重點是要理解保存和合並不會當即致使數據庫更新。更改一般由JPA緩存直到當前事務提交。而後更改被批量發送到數據庫,可是隻要有查詢在運行,未決更改也能夠經常被刷新。
   請注意一件有趣的事,咱們的Patient DAO對象對JPA API的依賴不多,由於Spring模板被用於全部數據訪問操做,它又內部委託給JPA。事實上,到目前爲止,咱們看到的對JPA的唯一直接依賴是getByLastName()方法使用的EJB QL查詢字符串。還請注意,雖然早些時候咱們將Spring DAO稱做POJO,可是這並不徹底正確,由於DAO須要擴展Spring的JpaDaoSupport類。然而,重要的是,暴露給應用程序其餘部分的接口DAO是不依賴於JPA或Spring類型的plain old Java interface。

JPA持久化類

  到目前爲止,咱們已經看到一些處理查詢和更新的示例數據訪問代碼,那麼持久化類又是什麼呢?想一想POJO和元數據。可是,持久化POJO須要遵循許多規則,或者說是設計模式。這些規則部分由JPA指定,而其餘的是根據整個應用架構的要求而產生的,正如咱們下面將看到的。
   首先是一條關於元數據的注意事項。JPA爲開發人員提供了幾種選項來指定與持久化和對象-關係映射相關的JPA元數據:在外部XML文件中指定、在Java 5.0註釋中指定,或者使用這兩者的組合。病歷應用程序使用JPA元數據的Java註釋。這樣作的好處是:元數據與應用該元數據的Java類、字段和方法一塊兒配置,這樣能夠幫助理解。若是想使元數據與代碼分離,可使用XML來代替。
   讓咱們考察一下Patient類及其字段聲明,看看示例註釋JPA類是什麼樣的:
package com.bea.medrec.domain; 
import javax.persistence.*;
import kodo.persistence.jdbc.ElementJoinColumn;
@Entity()
public class Patient implements Serializable
{
  @Id()
  @GeneratedValue(strategy=IDENTITY)
  private Integer id;
  private Date dob;
  @Column(name = "first_name")
  private String firstName;
  private String gender;
  @Column(name = "last_name")
  private String lastName;
  @Column(name = "middle_name")
  private String middleName;
  private String phone;
  private String ssn;
  @ManyToOne(cascade={PERSIST, MERGE})
  @JoinColumn (name="address_id")
  private Address address;
  @OneToOne(cascade={PERSIST, MERGE})
  @JoinColumn (name="email")
  private User user;
  @OneToMany(tar on getEntity = Prescription.class)
  @ElementJoinColumn(name="pat_id")
  private Set prescriptions=null;
  @OneToMany (targetEntity=Record.class)
  @ElementJoinColumn(name="pat_id")
  private Set records =null; 
  ...
}
  請注意,Patient類使用Entity註釋進行註釋。這是使用註釋的全部持久化類必須遵循的。Entity註釋的存在告訴持久化引擎該類是JPA實體。一般不要求Entity類是公有的,可是MedRec的持久化類須要是公有的,以便Web和Web服務層可使用它們。
   實體類還須要實現Serializable,可是因爲Patient類由MedRec struts操做置於HTTP會話中,因此它須要是可串行化的。這樣應用程序能夠在集羣環境中工做,其中會話狀態能夠在集羣中各節點之間進行串行化。關於實體類的其餘要求是:它必須是頂級類且不是final。請參閱JPA規範(JSR220)以得到完整的規則列表。

持久化字段

  JPA實現須要在運行時讀取和寫入實體類的狀態(持久化字段)。JPA規範容許實現或者經過直接訪問實體字段的方式或者經過調用JavaBean風格的accessor方法(getter/setter)的方式來進行此操做。使用的訪問方式由持久化註釋的位置決定。例如,若是註釋位於類的字段上,則使用字段訪問。
   您可能要問:爲何JPA支持字段和方法兩種訪問方式呢?答案是靈活性。一些類在它們的公有accessor方法中執行驗證。若是因爲數據庫中的值溢出而拋出異常,這可能致使JPA實現出現問題。若是類在其setter中執行驗證,則最好對字段進行註釋。另外一方面,若是但願支持虛擬持久化屬性之類的功能,那麼就註釋accessor方法。
   在JPA實體中,全部未使用Transient註釋(由JPA定義)進行註釋的非瞬態字段都是持久化字段。「持久化」意味着字段被映射到數據庫中的列。請注意,Patient類中的一些持久化字段沒有註釋。這是因爲JPA定義的默認值(如默認的列名稱)對於這些字段來講是正確的。若是字段名稱與其映射的數據庫列名稱不一樣,則必須使用Column註釋來爲數據庫列指定一個不一樣的列名稱。
   每一個實體必須具備主鍵。JPA支持簡單(單字段)和複合(多字段)的主鍵。若是能夠,最好一直使用簡單主鍵,並讓數據庫生成主鍵值。這是由於,一旦對象被保存,JPA就不容許更改主鍵值。因爲此緣由,病歷應用程序中的大多數持久化類(包括Patient類)都使用簡單的生成主鍵。關於具備複合主鍵的類的示例,請參考Group類。Id註釋用於標記主鍵字段或標識字段。
   GeneratedValue註釋用於表示在插入新的Patient時主鍵值是由數據庫生成的。數據庫能夠以數種方式生成主鍵值,可以使用strategy屬性來選擇其中一個。Patient類使用標識策略,這意味着id字段應被映射到數據庫自動-增量或標識列。
   在使用標識策略時,須要注意這對類的equals和hashcode方法所產生的影響。例如,若是equals方法比較id字段的值,請確保使用對象的方式不會致使equals方法在進行數據庫插入操做以前(一般在事務提交時)被調用,由於主鍵值直到這時才被分配。避免這種狀況的一種方法是,(若是類有的話)在equals方法中使用天然鍵而不是生成鍵。例如,Patient Social Security number是可用於Patient equals方法中的很好的天然鍵。

關係

  大多數實體具備與域模型中其餘的單個或多個實體的關係,Patient類也不例外。圖2展現了Patient類及其關係圖。
Patient類及其關係圖
圖2.Patient類關係
   JPA使用一對1、多對1、一對多和多對多註釋來指定關係及其基數。每一個關係字段必須使用這些註釋中的一個進行註釋。例如,Patient具備與Address的多對一關係。這意味着許多病人可能具備相同的地址。Patient與User類具備一對一關係,該類包含病人的用戶名和密碼信息。這意味着每一個Patient與單個的User相關。
   Patient具備與Prescriptions和Records的一對多關係,由於特定的病人能夠有多個處方,並可能屢次看醫生(這將致使建立病歷)。相反,每一個Prescription或Record只能夠與一個Patient關聯。

級聯操做

  JPA關係的一個有趣特性是操做的級聯。您可能已經熟悉了大多數關係數據庫所支持的「級聯刪除」特性。JPA採用了相似於刪除的級聯操做的理念,並將其應用於其餘操做(例如插入和更新)。Patient類將插入和關係操做級聯到相關的Address和User。在JPA中插入被視爲持久化,由於數據庫插入是在對對象持久化時執行的。更新被視做合併,由於更新將對象中的更改合併到當前JPA持久化上下文中。這看上去有些混亂,可是請別擔憂;只需記住:在但願更新已經被保存的對象時,要調用合併;當要在數據庫中插入新的持久化對象時,要調用持久化。
   肯定是否對特定操做(例如持久化、合併或移除)進行級聯是須要技巧的。在Patient類的狀況中,持久化被級聯到Address和User,由於應用程序也須要在插入Patient的地方插入新的Address和User。相似地,在更新Patient的時候,Address和User可能也須要更新。Prescriptions和Records則不一樣。應用程序具備顯式持久化(以及更新)Prescription或Record的操做,因此不須要將這些操做從Patient級聯到這些類。
  您可能還記得前一節中咱們曾說多個Patient被容許引用相同的Address——從Patient到Address的關係是多對一。可是,咱們剛剛也說了Patient將插入級聯到Address,這致使爲數據庫中的每位病人建立一個新地址。這是怎麼回事呢?您在這裏看到的是在Patient和Address之間使用生成的主鍵和級聯插入的有趣效果。由於用於地址的主鍵由數據庫自動生成,因此每一個Address將有唯一的主鍵,指向相同實際地址的兩個不一樣Address對象有可能都被插入到數據庫中。這對於許多應用程序(包括MedRec)來講沒什麼問題,可是若是您但願阻止複製這樣的地址,則DAO須要執行一些附加的邏輯。

Web Services注意事項

  JPA將MedRec的實體類映射到數據庫模式,而WebLogic Server 9.1 Web services實現將其映射到XML,這引起了一些影響實體類設計的其餘問題。
   JPA支持單向和雙向關係,可是若是考察MedRec中的實體類,會看到全部關係都是單向的。這是必要的,由於Web services綁定不支持雙向關係。
   因爲JPA要求Java Collection類型(如java.util.Set)用於多值關係字段,這引起了另外一個問題。實踐代表9.1中的Web services不支持Collection類型。那麼咱們如何解決這一問題呢?
   不知您是否還記得,對象-關係映射能夠在實體的字段或方法上定義。實踐代表,JPA的此靈活性很是重要。另外一方面,Web services使用類的公有屬性accessor方法(getXXX()方法)定義被封送爲XML的屬性。經過使用字段定義持久化映射以及由類上的方法定義XML綁定,咱們可以將兩個映射分離!多值關係爲了持久化在內部使用Set,可是能夠經過屬性訪問方法將其暴露爲XML綁定可以處理的數組。
   爲了具體說明,下面是一個來自Record類的執行此轉換的屬性訪問方法示例:
public Prescription[] getPrescriptions() {
   if (prescriptions == null)
      return null;
   return (Prescription[]) prescriptions.toArray(new 
      Prescription[prescriptions.size()]);
}
  此方法在內部訪問具備java.util.Set類型的持久化處方字段。此Set被轉換爲Web services實現可以處理的數組。關於Web services集成的體驗使咱們對JPA及其與現有應用程序和基礎架構集成的能力印象深入。
   如今對持久化類的討論就結束了。看起來彷佛須要遵循許多規則和限制,但事實上大多數JPA只是將好的編碼實踐具體化了,您可能會發現您沒有過多考慮就在遵循它們。

使用DAO實現服務

  如今咱們看到了如何使用Spring 2.0和JPA實現數據訪問對象,接下來讓咱們快速考察一下使用DAO的MedRec服務對象。如下的代碼示例顯示了PatientServiceImpl類及其業務方法之一,processNewRegistration方法:
public class PatientServiceImpl 
   extends BaseService implements PatientService {
 
    protected PatientDao patientDao;
    public void setPatientDao(PatientDao patientDao) {
        this.patientDao = patientDao;
    }
    
    public void processNewRegistration(Registration registration) {
      try {
         User user = registration.getUser();
         Patient patient = registration.getPatient();
         patient.setUser(user);
         user.setStatus(MedRecConstants.USER_NEW);
            
         patientDao.save(pPatient);
      } catch (Exception ex) {
        ...
      }
   }
   
   ...
}
  當新病人使用MedRec Web接口自我註冊時會調用processNewRegistration方法。它將保存新病人註冊信息的Registration對象做爲參數。ProcessNewRegistration首先從Registration對象獲取Patient和User,並初始化它們之間的關係。User對象包含病人的用戶名和密碼信息,還保存被設置爲USER_NEW的病人狀態,由於這是位必須由管理員批准的新病人。而後調用Patient DAO將新的病人插入到數據庫。
   針對MedRec服務對象對Spring聲明式事務進行配置,以便在調用業務方法(如processNewRegistration)以前由Spring啓動事務,並在此方法完成時提交該事務。這確保了DAO做爲可自動提交的現有事務的一部分而運行。還請注意Spring所使用的、將對DAO對象的引用注入服務bean中的setPatientDao方法。

配置

  到目前爲止,咱們已經考察了一些構成此版本的病歷應用程序的Java代碼。本節將爲您介紹Spring和Kodo要求的外部配置。咱們從Spring開始。

Spring配置

  咱們使用一組模塊化XML配置文件來配置Spring ApplicationContext。包含數據訪問對象配置的配置文件是applicationContext-orm.xml,它位於MedRec安裝目錄下的src\medrecEar\APP-INF\classes目錄中。如下是applicationContext-orm.xml中聲明Patient DAO的片斷:
<bean id="patientDao"
      class="com.bea.medrec.dao.orm.JpaPatientDao"
      autowire="byType"/>
  Spring的JPA DAO具備須要被注入的單一依賴,即JPA EntityManagerFactory。DAO使用此EntityManagerFactory建立執行實際持久化工做的JPA EntityManagers。這裏使用Spring自動綁定特性完成綁定,這就是爲何咱們在XML中看不到對EntityManagerFactory的顯式依賴。自動綁定特性自動將DAO綁定到基於DAO的EntityManagerFactory屬性(繼承自全部MedRec DAO類對其進行擴展的Spring JpaDaoSupport類)類型的EntityManagerFactory。
   如下代碼是聲明建立EntityManagerFactory的Spring工廠bean的片斷。因爲這裏討論了兩個工廠,可能聽起來有些混亂,可是請記住:Spring工廠bean的目的就是提供一箇中間層,以便容許咱們執行某些自定義代碼以建立EntityManagerFactory。此EntityManagerFactory是DAO對象唯一知道或關心的工廠。
<bean id="entityManagerFactory"
      class="com.bea.medrec.utils.KodoEntityManagerFactoryBean">
  <property name="jndiName">
     <value>kodo-jpa</value>
  </property>  
</bean>
  由於在撰寫本文的時候,WebLogic Server不支持與JPA的標準集成,因此EntityManagerFactory經過使用自定義工廠bean而建立。EntityManagerFactory須要知道在JNDI中的什麼地方查找Kodo資源適配器。該信息被配置爲Spring工廠bean上的屬性,後者將其傳送到EntityManagerFactory。請記住,工廠bean的任務是建立EntityManagerFactory事件並將其返回到Spring,以使Spring可以將EntityManagerFactory注入DAO bean。用於建立實體管理器工廠實例的工廠bean代碼以下所示:
public class KodoEntityManagerFactoryBean 
   implements FactoryBean, InitializingBean {
   private String jndiName = "kodo-jpa";
   private EntityManagerFactory entityManagerFactory = null;
   public void setJndiName(String jndiName) {
      this.jndiName = jndiName;
   } 
   public Object getObject() throws Exception {
      return entityManagerFactory;
   }
   public Class getObjectType() {
      return EntityManagerFactory.class;
   }
   public boolean isSingleton() {
      return true;
   } 
   public void afterPropertiesSet() throws Exception {
      try {
         entityManagerFactory  =
            KodoPersistence.createEntityManagerFactory(
               jndiName, new InitialContext());
      } catch (Throwable throwable) {
         throw new RuntimeException(throwable);
      }
   }
}
  KodoEntityManagerFactoryBean是一個至關簡單的Spring工廠bean。在運行時,Spring首先調用默認的構造函數建立bean實例。而後,Spring調用setJndiName()方法設置Kodo資源適配器的JNDI名稱。一旦全部屬性被注入,Spring就調用建立EntityManagerFactory實例的afterPropertiesSet()。最後,Spring調用getObject()來獲取將被注入DAO的EntityManagerFactory。
   咱們已經看到了如何使用Kodo EntityManagerFactory(DAO使用它來完成全部持久化工做)注入Spring DAO。而後Kodo EntityManagerFactory經過JNDI鏈接到Kodo資源適配器。接下來,咱們將考察Kodo資源適配器的配置,可是首先須要知道一點關於Spring配置的其餘內容,這將有助於將全部事情聯繫起來。
   Spring須要被告知使用WebLogic JTA事務管理器來啓動和提交事務。此操做在如下的XML片斷中完成:
<bean id="transactionManager"
      class="org.springframework.transaction.jta.WebLogicJtaTransactionManager">
  <property name="transactionManagerName"
    value="javax.transaction.TransactionManager"/>
</bean>
  這裏要明白一件重要的事情,即,須要專門告訴Spring將事務工做委託給WebLogic JTA實現。稍後,咱們將看到Kodo也被告知在其配置中使用JTA事務。這將安排好事情以便MedRec服務對象啓動WebLogic JTA事務,而後在此事務中調用DAO。隨後DAO調用Kodo,它做爲現有WebLogic JTA事務的一部分執行數據庫讀出和寫入。

Kodo配置

  咱們使用Kodo 4.0 EA4,它是Kodo的JPA實現的早期訪問版本。在撰寫本文的時候,定義JPA的EJB 3.0規範還沒有完成,因此Kodo支持JPA的pre-final版本。Kodo做爲資源適配器被部署到WebLogic Server。此資源適配器在JNDI中進行註冊。資源適配器的配置在標準ra.xml描述符文件中進行,它位於資源適配器RAR文件的META-INF目錄中。
   若是考察ra.xml文件,會看到Kodo支持多種配置選項(成熟產品的標誌)。然而,示例應用程序僅須要咱們修改其中的一小部分。讓咱們看看示例應用程序須要的屬性:
<config-property>
   <config-property-name>ConnectionFactory2Name</config-property-name>
   <config-property-type>java.lang.String</config-property-type>
   <config-property-value>jdbc/MedRecGlobalDataSource
   </config-property-value>
</config-property>
<config-property>
   <config-property-name>ConnectionFactoryName</config-property-name>
   <config-property-type>java.lang.String</config-property-type>
   <config-property-value>jdbc/MedRecGlobalDataSourceXA
   </config-property-value>
</config-property>
<config-property>
   <config-property-name>TransactionMode</config-property-name>
   <config-property-type>java.lang.String</config-property-type>
   <config-property-value>managed</config-property-value>
</config-property>
<config-property>
   <config-property-name>LicenseKey</config-property-name>
   <config-property-type>java.lang.String</config-property-type>
   <config-property-value>XXXXXXXXXXXXXXXXXXXX</config-property-value>
</config-property>
<config-property>
   <config-property-name>PersistentClasses</config-property-name>
   <config-property-type>java.lang.String</config-property-type>
   <config-property-value>
      com.bea.medrec.domain.Patient,com.bea.medrec.domain.Address,
      com.bea.medrec.domain.User,com.bea.medrec.domain.Physician,
      com.bea.medrec.domain.Prescription,com.bea.medrec.domain.Record,
      com.bea.medrec.domain.Group,com.bea.medrec.domain.VitalSigns
   </config-property-value>
</config-property>
  Kodo須要被告知JDBC數據源的JNDI位置,以便它可以與數據庫交互。事實上,Kodo須要知道兩個數據源:一個數據源用於處理事務工做,另外一個用於非事務工做,由於Kodo有時訪問數據庫執行不屬於全局事務的工做。您可能已經猜到了,ConnectionFactoryName和ConnectionFactory2Name屬性正是用於此目的。每一個屬性的值是WebLogic數據源的JNDI名稱。請確保ConnectionFactory2Name引用的數據源不將其鏈接加入全局JTA事務。
   Kodo還須要知道此應用程序是否正在使用JTA管理的事務或本地事務。由於控制事務的MedRec服務bean被配置爲使用JTA,因此咱們將TransactionMode屬性值設爲託管。此外,還須要在資源適配器文件中配置Kodo許可,並列出應用程序將使用的持久化類。用於此用途的屬性應該是自解釋的。
   若是您曾經考察過JPA規範,您可能據說過persistence.xml文件。這是包含與JPA持久化相關的元數據的標準配置文件。Kodo還支持persistence.xml文件。然而,在應用服務器環境中使用Kodo的當前早期訪問版本時,persistence.xml文件僅包含資源適配器配置中指定的信息的子集,且只能經過工具(例如Kodo加強程序)使用。

下載

  如下下載包括本文所討論的MedRec版本的全部Java和其餘源文件,以及Spring 2.0和Kodo二進制文件及其依賴性: medrec-spring-jpa.zip。您大概須要27MB的磁盤空間來存放下載文件。

結束語

  本文詳細考察了對Spring 2.0中的新增JPA支持的使用,該特性被用於從新實現MedRec示例應用程序的數據訪問層。但願本文爲您提供了開始使用這些新API所需的信息。若是您但願進行更深刻地研究,咱們建議您考察本文所包含的實際MedRec代碼。示例應用程序代碼演示瞭如何以集成方式協同使用WebLogic 9.一、Spring 2.0和Kodo JPA。
   咱們已經看到新的JPA API易用、直觀且具備靈活性。Java註釋在下降指定數據庫映射所需的元數據數量方面表現突出。雖然JPA是新增的,可是其強大功能足以容許咱們繼續在持久化層、Web層和Web服務層中的應用程序中使用域模型類。此重用大大簡化了應用架構,並顯著下降了開發人員須要編寫的Java類的數量。
   而Spring 2.0方面提供了一個利用JPA建立數據訪問對象的優秀工具。Spring的數據訪問架構使得咱們能夠輕鬆地在不一樣持久化技術之間進行轉換,而無需重寫其餘應用程序代碼。

參考資料

 做者簡介
icon
Seth White
Seth White 是BEA的高級工程師,近6年來,他是WebLogic Server工程團隊的成員。目前他是WebLogic Server開源團隊的成員。
相關文章
相關標籤/搜索