<rt id="bn8ez"></rt>
<label id="bn8ez"></label>

  • <span id="bn8ez"></span>

    <label id="bn8ez"><meter id="bn8ez"></meter></label>

    kapok

    垃圾桶,嘿嘿,我藏的這么深你們還能找到啊,真牛!

      BlogJava :: 首頁 :: 新隨筆 :: 聯(lián)系 :: 聚合  :: 管理 ::
      455 隨筆 :: 0 文章 :: 76 評(píng)論 :: 0 Trackbacks
    http://www-128.ibm.com/developerworks/cn/java/j-hibernate/?ca=dwcn-newsletter-java

    內(nèi)容:
    概述
    我們的支持示例
    策略 1: 每個(gè)子類一個(gè)表(Persons)
    策略 2:每個(gè)類層次結(jié)構(gòu)一個(gè)表(Rights)
    數(shù)據(jù)庫模型的完整性
    策略 3: 每個(gè)具體類一個(gè)表(Estates)
    多態(tài) —— 用到極限!
    結(jié)束語
    參考資料
    下載
    作者簡介
    對(duì)本文的評(píng)價(jià)
    相關(guān)內(nèi)容:
    無需容器的對(duì)象關(guān)系映射
    Using Hibernate to persist your Java objects to IBM DB2 Universal Database
    Developing Hibernate application for use with WebSphere Application Server
    IBM developer kits for the Java platform (downloads)
    訂閱:
    developerWorks 時(shí)事通訊
    學(xué)習(xí)映射類層次結(jié)構(gòu)的三個(gè)易于實(shí)現(xiàn)的策略

    級(jí)別: 初級(jí)

    Xavier Coulon, 電子商務(wù) IT 專家, IBM Business Consulting Services
    Christian Brousseau, J2EE 顧問

    2005 年 1 月 14 日

    Hibernate 是一個(gè)對(duì)象關(guān)系映射和持久性框架,它提供了許多高級(jí)特性,從內(nèi)省到多態(tài)和繼承映射。但是,把類的層次結(jié)構(gòu)映射到關(guān)系數(shù)據(jù)庫模型,可能會(huì)比較困難。本文將介紹三個(gè)策略,在日常的編程之中您可以用它們把復(fù)雜的對(duì)象模型容易地映射到關(guān)系數(shù)據(jù)庫模型。

    概述
    Hibernate 是一個(gè)純 Java 的對(duì)象關(guān)系映射和持久性框架,它允許您用 XML 配置文件把普通 Java 對(duì)象映射到關(guān)系數(shù)據(jù)庫表。使用 Hibernate 能夠節(jié)約大量項(xiàng)目開發(fā)時(shí)間,因?yàn)檎麄€(gè) JDBC 層都由這個(gè)框架管理。這意味著您的應(yīng)用程序的數(shù)據(jù)訪問層位于 Hibernate 之上,完全是從底層數(shù)據(jù)模型中抽象出來的。

    比起其他類似的對(duì)象關(guān)系映射技術(shù)(JDO、實(shí)體 bean、內(nèi)部開發(fā)等),Hibernate 有許多優(yōu)勢(shì):它是免費(fèi)的、開源的,已經(jīng)成熟到良好的程度,并得到廣泛應(yīng)用,而且還有一個(gè)非常活躍的社區(qū)論壇。

    要把 Hibernate 集成到現(xiàn)有的 Java 項(xiàng)目,則需要執(zhí)行以下步驟:

    1. 從 Hibernate 的 Web 站點(diǎn)下載 Hibernate 框架的最新發(fā)行版(請(qǐng)參閱 參考資料一節(jié)中的鏈接。)

    2. 把必需的 Hibernate 庫(JAR 文件)復(fù)制到應(yīng)用程序的 CLASSPATH。

    3. 創(chuàng)建 XML 配置文件,用它把 Java 對(duì)象映射到數(shù)據(jù)庫表。(我們將在本文中描述這個(gè)過程。)

    4. 把 XML 配置文件復(fù)制到應(yīng)用程序的 CLASSPATH。

    您會(huì)注意到,不必修改任何 Java 對(duì)象,您就可以支持框架。例如,假設(shè)您對(duì) Java 應(yīng)用程序使用的數(shù)據(jù)庫表做了些修改 —— 例如修改了列名。在修改完表之后,您要做的只是更新對(duì)應(yīng)的 XML 配置文件。 您不需要重新編譯任何 Java 代碼。

    Hibernate 查詢語言(HQL)
    Hibernate 提供了一個(gè)查詢語言,叫作 Hibernate 查詢語言(HQL),它與 SQL 很相似。如果您喜歡用老式的 SQL 查詢,那么 Hibernate 也為您提供了使用它們的機(jī)會(huì)。但是我們使用的示例只用 HQL。

    HQL 用起來相當(dāng)簡單。您會(huì)發(fā)現(xiàn)所有的關(guān)鍵字都與您熟悉的 SQL 中的關(guān)鍵字類似,例如 SELECTFROMWHERE。HQL 與 SQL 的差異在于,您不用針對(duì)數(shù)據(jù)模型(即針對(duì)表和列等)直接編寫查詢,而是應(yīng)該針對(duì) Java 對(duì)象,使用 Java 對(duì)象的屬性和關(guān)系編寫查詢。

    清單 1 演示了一個(gè)基本的示例。這個(gè) HQL 代碼檢索 firstName 為 “John.” 的所有 Individual

    清單 1. 基本 HQL 查詢
    
    SELECT * FROM eg.hibernate.mapping.dataobject.Individual WHERE firstName = "John"
    

    如果想了解更多有關(guān) HQL 語法的內(nèi)容,那么您可以參閱 Hibernate 的 Web 站點(diǎn)上有關(guān) HQL 的參考材料(請(qǐng)參閱 參考資料,以獲得鏈接)。

    XML 配置文件
    功能的核心在于 XML 配置文件。這些文件必須存在于應(yīng)用程序的 CLASSPATH 中。我們把它們放在示例代碼包的 config 目錄中(您可以從 參考資料下載)。

    我們要研究的第一個(gè)文件是 hibernate.cfg.xml。它包含與數(shù)據(jù)源有關(guān)的信息(數(shù)據(jù)庫 URL、模式名稱、用戶名、口令等),以及對(duì)包含映射信息的其他配置文件的引用。

    其余的 XML 文件允許您把 Java 類映射到數(shù)據(jù)庫表。稍后我再深入介紹這些文件,但重要的是要清楚它們的文件名要遵守 ClassName.hbm.xml 這個(gè)模式。

    我們的支持示例
    在本文中,我們要研究一個(gè)基本示例,演示 Hibernate 如何工作,如何良好地運(yùn)用三個(gè)不同策略,利用 Hibernate 進(jìn)行對(duì)象關(guān)系映射。我們的示例是一家保險(xiǎn)公司使用的應(yīng)用程序,公司必須保持客戶投保的所有產(chǎn)權(quán)的法律記錄。我們隨本文提供了完整的源代碼(請(qǐng)參閱 參考資料);這個(gè)代碼提供了基本功能,您可以根據(jù)它構(gòu)建全功能的應(yīng)用程序,例如 Web 或 Swing 應(yīng)用程序。

    我們的示例采用了這類應(yīng)用程序的經(jīng)典用例。用戶提供搜索參數(shù),查找各種類型的客戶(個(gè)人、公司、政府機(jī)構(gòu)等),然后顯示與指定參數(shù)匹配的所有客戶列表 —— 即使這些客戶的類型不同。用戶可以訪問同一列表中的某一特定客戶更加詳細(xì)的視圖。

    在我們的應(yīng)用程序中,產(chǎn)權(quán)由 Right 類表示。 Right 可以是 Lease 也可以是 PropertyRight 由客戶所有。為了表示我們的客戶,我們要使用通用類 PersonPerson 即可以是 Individual 也可以是 Corporation。當(dāng)然,保險(xiǎn)公司必須知道這些 Right 被分配給哪個(gè) Estate。您應(yīng)當(dāng)同意, Estate 這個(gè)術(shù)語代表的意義非常泛。所以,我們要用 LandBuilding 類給我們的開發(fā)人員提供更具體的操作對(duì)象。

    從這個(gè)抽象出發(fā),我們可以開發(fā)圖 1 所示的類模型:

    圖 1. 完整的類模型
    完整的類模型

    我們的數(shù)據(jù)庫模型是為了介紹將在本文中討論的三個(gè)不同策略而設(shè)計(jì)的。對(duì)于 Right 層次結(jié)構(gòu)來說,我們要使用一個(gè)表( TB_RIGHT),并用 DISCRIMINATOR 列映射到正確的類。對(duì)于 Person 結(jié)構(gòu),我們要使用一個(gè)稱為 超表TB_PERSON)的表,它與另外兩個(gè)表( TB_CORPORATIONTB_INDIVIDUAL)共享相同的 ID。第三個(gè)層次結(jié)構(gòu)( Estate)使用兩個(gè)不同的表( TB_BUILDINGTB_LAND),這兩個(gè)表通過由兩個(gè)列( REF_ESTATE_IDREF_ESTATE_TYPE)組合定義的外鍵連接在一起。

    圖 2 顯示了這個(gè)數(shù)據(jù)模型:

    圖 2. 完整的數(shù)據(jù)模型
    完整的數(shù)據(jù)模型

    設(shè)置數(shù)據(jù)庫
    Hibernate 支持各種各樣的 RDBMS,其中任何一種都可以使用我們的示例。但是,本文的示例代碼和文本已經(jīng)針對(duì) HSQLDB(請(qǐng)參閱 參考資料查找鏈接)進(jìn)行了調(diào)整,這是一個(gè)完全用 Java 語言編寫的全功能的關(guān)系數(shù)據(jù)庫系統(tǒng)。在示例代碼包的 sql 目錄中,可以找到叫作 datamodel.sql 的文件。這個(gè) SQL 腳本可以創(chuàng)建我們示例中使用的數(shù)據(jù)模型。

    設(shè)置 Java 項(xiàng)目
    雖然您總能用命令行構(gòu)建并執(zhí)行示例代碼,但是您可能想在 IDE 中設(shè)置項(xiàng)目,以便更好地進(jìn)行集成。在示例代碼包里,您可以找到以下目錄:

    • config,包含樣本的所有 XML 配置文件(映射、Log4J 等)。

    • data,包含 HSQLDB 使用的配置文件。您還可以找到一個(gè)叫作 startHSQLDB.bat 的批處理文件,您可以用它啟動(dòng)數(shù)據(jù)庫。

    • src,包含示例的所有源代碼。

    請(qǐng)確保把必需的 Java 庫和 XML 配置文件復(fù)制到應(yīng)用程序的 CLASSPATH。只需要 Hibernate 和 HSQLDB 庫,這些代碼就可以正確地編譯和運(yùn)行。您可以從 參考資料一節(jié)下載這些包。

    策略 1: 每個(gè)子類一個(gè)表(Persons)
    在我們第一個(gè)策略中,我們要看看如何映射我們的 Person 層次結(jié)構(gòu)。您會(huì)注意到,數(shù)據(jù)模型與我們的類模型非常接近。所以,我們要為層次結(jié)構(gòu)中的每個(gè)類采用一個(gè)不同的表,但是所有這些表都必須共享相同的主鍵(我們很快就會(huì)詳細(xì)說明)。Hibernate 在向數(shù)據(jù)庫中插入新記錄時(shí),就會(huì)使用這個(gè)主鍵。在訪問數(shù)據(jù)庫時(shí),它還會(huì)利用同一主鍵執(zhí)行 JOIN 操作。

    現(xiàn)在我們需要把對(duì)象層次結(jié)構(gòu)映射到表模型。我們有三個(gè)表( TB_PERSONTB_INDIVIDUAL、和 TB_CORPORATION)。前面我們提過,它們都有一個(gè)叫作 ID 的列,并將該列作為主鍵。表之間不一定非要有這樣的共享列名稱,但是這是一個(gè)很好的實(shí)踐 —— 這樣做的話,生成的 SQL 查詢更容易閱讀。

    在清單 2 所示的 XML 映射文件中,您會(huì)注意到,在 Person 的映射定義中,聲明了兩個(gè)具體的 <joined-subclass> 類。XML 元素 <id> 映射到頂級(jí)表 TB_PERSON 的主鍵,同時(shí) <key> 元素(來自每個(gè)子類)映射到 TB_INDIVIDUALTB_CORPORATION 表中匹配的主鍵。

    清單 2. Person.hbm.xml
    
    <?xml version="1.0" encoding="UTF-8"?>
    <!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 2.0//EN"
    	"http://hibernate.sourceforge.net/hibernate-mapping-2.0.dtd">
    
    <hibernate-mapping>
      <class name="eg.hibernate.mapping.dataobject.Person" table="TB_PERSON" polymorphism="implicit">
        <id name="id" column="ID">
          <generator class="assigned"/>
        </id>
        <set name="rights" lazy="false">
          <key column="REF_PERSON_ID"/>
          <one-to-many class="eg.hibernate.mapping.dataobject.Right" />
        </set>
        
            <joined-subclass name="eg.hibernate.mapping.dataobject.Individual" table="TB_INDIVIDUAL">
          <key column="id"/>
          <property name="firstName" column="FIRST_NAME" type="java.lang.String" />
          <property name="lastName" column="LAST_NAME" type="java.lang.String" />
        </joined-subclass>
        
            <joined-subclass name="eg.hibernate.mapping.dataobject.Corporation" table="TB_CORPORATION">
          <key column="id"/>
          <property name="name" column="NAME" type="string" />
          <property name="registrationNumber" column="REGISTRATION_NUMBER" type="string" />
        </joined-subclass>
      </class>
    </hibernate-mapping>
    
          

    保存 Individual 的一個(gè)新實(shí)例,形成我們使用 Hibernate 的 Java 代碼非常容易,如清單 3 所示:

    清單 3. 保存 Individual 的一個(gè)新實(shí)例
    
    public Object create(Object object) {
      Session session = null;
      try {
        session = sessionFactory.openSession();
        Transaction tx = session.beginTransaction();
        
            session.save(object);
        session.flush();
        tx.commit();
        ...
    }
    
          

    接著,Hibernate 生成兩個(gè) SQL INSERT 請(qǐng)求,如清單 4 所示。這兩個(gè)請(qǐng)求面向的是一個(gè) save()

    清單 4. SQL 插入查詢
    
    insert into TB_PERSON (ID) values (?)
    insert into TB_INDIVIDUAL (FIRST_NAME, LAST_NAME, id) values (?, ?, ?)
    

    要想訪問數(shù)據(jù)庫中的 Individual,只需在 HQL 查詢中指定類名即可,如清單 5 所示。

    清單 5. 調(diào)用 HQL 查詢
    
    public Person findIndividual(Integer id) {
      ...
      session.find(
            "select p from " + Individual.class.getName() + " as p where p.id = ?",
        new Object[] { id },
        new Type[] { Hibernate.INTEGER });	
      ...
    }
    
          

    Hibernate 會(huì)自動(dòng)執(zhí)行 SQL 的 JOIN,從兩個(gè)表中檢索所有必要信息,如清單 6 所示:

    清單 6. 查找 Individual 的 SQL SELECT 查詢
    
    select individual0_.id as ID, individual0_.FIRST_NAME as FIRST_NAME55_, 
      individual0_.LAST_NAME as LAST_NAME55_ 
      from TB_INDIVIDUAL individual0_ 
      
            inner join TB_PERSON individual0__1_ on individual0_.id=individual0__1_.ID 
      where (individual0_.id=? )
    
          

    查詢抽象類
    當(dāng)查詢抽象類時(shí),Hibernate 會(huì)自動(dòng)返回一個(gè)集合,由匹配的具體異構(gòu)子類構(gòu)成。例如,如果我們查詢數(shù)據(jù)庫中的每個(gè) Person,Hibernate 會(huì)返回一列 IndividualCorporation 對(duì)象。

    但是,當(dāng)沒有指定具體類時(shí),Hibernate 需要執(zhí)行 SQL 的 JOIN,因?yàn)樗恢酪樵兡膫€(gè)表。在 HQL 查詢返回的檢索到的所有表的列中,還會(huì)返回一個(gè)額外的 dynamic 列。Hibernate 使用 clazz 列來初始化和填充返回的對(duì)象。我們把這個(gè)類叫作決定因子(determination dynamic),與我們?cè)诘诙€(gè)策略中使用的方法相對(duì)。

    清單 7 顯示了如何指定抽象類的 id 屬性查詢抽象類 Person,清單 8 顯示了 Hibernate 自動(dòng)生成的 SQL 查詢,其中包括表連接:

    清單 7. find() 方法調(diào)用中的 HQL 查詢
    
    public Person find(Integer id) {
      ...
      session.find(
            "select p from " + Person.class.getName() + " as p where p.id = ?",
        new Object[] { id },
        new Type[] { Hibernate.INTEGER });	
      ...
    }
    
          
    清單 8. 查找任何類型的 Person 的 SQL SELECT 查詢
    
    select person0_.ID as ID0_,
            
      casewhen(person0__1_.id is not null, 1,  
      casewhen(person0__2_.id is not null, 2,  
      casewhen(person0_.ID is not null, 0, -1))) as clazz_0_, 
      person0__1_.FIRST_NAME as FIRST_NAME61_0_, 
      person0__1_.LAST_NAME as LAST_NAME61_0_, 
      person0__2_.NAME as NAME62_0_, 
      person0__2_.REGISTRATION_NUMBER as REGISTRA3_62_0_ 
      from TB_PERSON person0_ 
      left outer join TB_INDIVIDUAL person0__1_ on person0_.ID=person0__1_.id 
      left outer join TB_CORPORATION person0__2_ on person0_.ID=person0__2_.id 
      where person0_.ID=?
    
          

    策略 2:每個(gè)類層次結(jié)構(gòu)一個(gè)表(Rights)
    對(duì)于我們的 Right 層次結(jié)構(gòu),我們只使用一個(gè)表( TB_RIGHT)來保存整體類層次結(jié)構(gòu)。您會(huì)注意到, TB_RIGHT 表擁有保存 Right 類層次結(jié)構(gòu)的每個(gè)屬性所需要的所有列。保存的實(shí)例值也就會(huì)保存在表中,每個(gè)沒有使用的列則用 NULL 值填充。(因?yàn)樗教幎际恰岸础保晕覀兘?jīng)常把它叫作 瑞士奶酪表

    在圖 3 中,您會(huì)注意到, TB_RIGHT 表中包含一個(gè)額外的列 DISCRIMINATOR。Hibernate 用這個(gè)列自動(dòng)初始化對(duì)應(yīng)的類并相應(yīng)進(jìn)行填充。這個(gè)類用映射文件中的 XML 元素 <discriminator> 進(jìn)行映射。

    圖 3. TB_RIGHT 表的內(nèi)容
    TB_RIGHT 表的內(nèi)容

    簡明性技巧
    在每個(gè)大型項(xiàng)目中,您都會(huì)面臨包含多級(jí)抽象類的復(fù)雜的類層次結(jié)構(gòu)。幸運(yùn)的是,您不必指定抽象類的 discriminator-value,只需為 Hibernate 實(shí)際要使用的具體類指定這個(gè)值即可。

    正如清單 2 所示的 Person 映射文件,在清單 9 中,我們映射了抽象類( Right)及其所有屬性。要映射兩個(gè)具體類( LeaseProperty),就要使用 <subclass> XML 標(biāo)簽。這個(gè)標(biāo)簽非常簡單;它要求 name 屬性,僅僅是因?yàn)?class 標(biāo)簽要求 discriminator-value 屬性。Hibernate 將用后一個(gè)屬性標(biāo)識(shí)它要處理的類。

    圖 1 的類圖中您會(huì)注意到, discriminator 不是任何 Java 類都有的屬性。實(shí)際上,它甚至沒有映射。它僅僅是 Hibernate 和數(shù)據(jù)庫之間共享的一個(gè)技術(shù)性的列。

    清單 9. Right.hbm.xml
    
    <?xml version="1.0" encoding="UTF-8"?>
    <!DOCTYPE hibernate-mapping PUBLIC 
      "-//Hibernate/Hibernate Mapping DTD 2.0//EN"
      "http://hibernate.sourceforge.net/hibernate-mapping-2.0.dtd">
    <hibernate-mapping>
      <class name="eg.hibernate.mapping.dataobject.Right" table="TB_RIGHT" polymorphism="implicit">
        <id name="id" column="ID">
          <generator class="assigned"/>
        </id>
        
            <discriminator>
          <column name="DISCRIMINATOR"/>
        </discriminator>
        <property name="date" column="DATE" type="java.sql.Date" />
        <many-to-one name="person" class="eg.hibernate.mapping.dataobject.Person" column="REF_PERSON_ID"/>
        <any name="estate"
             meta-type="string"
             id-type="java.lang.Integer">
          <meta-value value="LND" class="eg.hibernate.mapping.dataobject.Land"/>
          <meta-value value="BLD" class="eg.hibernate.mapping.dataobject.Building"/>
          <column name="REF_ESTATE_TYPE"/>
          <column name="REF_ESTATE_ID"/>          
        </any>
        
        
            <subclass name="eg.hibernate.mapping.dataobject.Property" discriminator-value="PRO"/>
        
        <subclass name="eg.hibernate.mapping.dataobject.Lease" discriminator-value="LEA">
          <property name="duration" column="DURATION" type="java.lang.Integer" />
         
            </subclass>
      </class>
    </hibernate-mapping>
    
          

    在清單 9 的映射文件中,您會(huì)注意到 RightPerson 層次結(jié)構(gòu)之間的“多對(duì)一”關(guān)系,它(實(shí)質(zhì)上)與 Person 層次結(jié)構(gòu)(一對(duì)多)的關(guān)系正好相反。還請(qǐng)注意 RightEstate 層次結(jié)構(gòu)之間的關(guān)系;稍后我們將在本文中介紹這層關(guān)系。

    使用第一個(gè)策略時(shí),Hibernate 在訪問數(shù)據(jù)庫時(shí)生成了非常有效的 SQL 語句。當(dāng)我們查詢具體類時(shí),如清單 10 所示,會(huì)在 discriminator 的 Hibernate 過濾器上自動(dòng)取值 —— 這是件好事,因?yàn)檫@意味著 Hibernate 只讀取與指定類對(duì)應(yīng)的列。

    清單 10. 針對(duì)具體類的 SQL 查詢
    
    select property0_.ID as ID, property0_.DATE as DATE, 
    	property0_.REF_PERSON_ID as REF_PERS4_, property0_.REF_ESTATE_TYPE as REF_ESTA5_, 
    	property0_.REF_ESTATE_ID as REF_ESTA6_ 
    	from TB_RIGHT property0_ where property0_.DISCRIMINATOR='PRO'
    

    當(dāng)我們查詢抽象類時(shí),事情變得有些復(fù)雜。因?yàn)?Hibernate 不知道您要查詢哪個(gè)特定的類,所以必須讀取每個(gè)列(包括 discriminator 類),然后才能決定要初始化哪個(gè)類,最后再填充它。接下來,discriminator 充當(dāng)?shù)慕巧c第一個(gè)策略中 clazz 列充當(dāng)?shù)慕巧嗤5沁@個(gè)方法顯然更死板,因?yàn)轭惷苯优缮?discriminator 的值。

    清單 11. (抽象的) Right 類的 SQL 查詢
    
    select right0_.ID as ID, 
    	right0_.DISCRIMINATOR as DISCRIMI2_, 
    	right0_.DATE as DATE, right0_.REF_PERSON_ID as REF_PERS4_, 
    	right0_.REF_ESTATE_TYPE as REF_ESTA5_, right0_.REF_ESTATE_ID as REF_ESTA6_, 
    	right0_.DURATION as DURATION from TB_RIGHT right0_
    

    策略的不兼容
    按照 Hibernate 映射的 DTD 定義,本文中描述的前兩個(gè)策略是相互排斥的,這意味著它們無法組合在一起,映射同一個(gè)層次結(jié)構(gòu)。

    數(shù)據(jù)庫模型的完整性
    關(guān)于第二個(gè)策略,有一個(gè)需要重點(diǎn)考慮的地方:為了讓它工作,必須把所有非共享列設(shè)置為 NULLABLE。因?yàn)殚_發(fā)人員通常會(huì)依賴數(shù)據(jù)庫的約束,所以生成的表可能非常難以處理。(畢竟,把有持續(xù)時(shí)間的 Lease 設(shè)置為 NULL 沒多大意義!)

    解決方案之一是用 數(shù)據(jù)庫級(jí)檢測約束。您可以根據(jù) DISCRIMINATOR 的值,定義一套要實(shí)施的規(guī)則,如清單 12 所示。當(dāng)然,數(shù)據(jù)庫引擎必須支持這些特性。而且,由于必須同時(shí)為全部具體類用一個(gè)有效表達(dá)式表示這些約束,所以當(dāng)層次結(jié)構(gòu)發(fā)展的時(shí)候,維護(hù)會(huì)很困難。

    清單 12. 數(shù)據(jù)完整性約束
    
    alter table TB_RIGHT 
    	add constraint CHK_RIGHT check(	
    		(discriminant ='DPP' and date is null and duration is null)
    	or	(discriminant ='DLM' and date is not null and duration is not null));
    

    策略 3: 每個(gè)具體類一個(gè)表(Estates)
    我們的第三個(gè),也是最后一個(gè)策略可能是三個(gè)策略當(dāng)中最有想象力的:每個(gè)具體類一個(gè)表,抽象超類 Estate 沒有表。我們依靠 Hibernate 提供對(duì) 多態(tài)(polymorphism)的支持。在清單 3 所示的 XML 映射文件中,您會(huì)注意到,其中只映射了兩個(gè)具體類( BuildingLand):

    清單 13. Estate.hbm.xml
    
    <?xml version="1.0" encoding="UTF-8"?>
    <!DOCTYPE hibernate-mapping PUBLIC 
      "-//Hibernate/Hibernate Mapping DTD 2.0//EN"
      "http://hibernate.sourceforge.net/hibernate-mapping-2.0.dtd">
    
    <hibernate-mapping>
      <class name="eg.hibernate.mapping.dataobject.Land" table="TB_LAND" polymorphism="implicit">
        <id name="id" column="ID">
          <generator class="assigned"/>
        </id>
        <property name="description" column="DESCRIPTION" type="java.lang.String" />
        <property name="squareFeet" column="SQUARE_FEET" type="java.lang.Double"/>
      </class>
    
      <class name="eg.hibernate.mapping.dataobject.Building" table="TB_BUILDING" polymorphism="implicit">
        <id name="id" column="ID">
          <generator class="assigned"/>
        </id>
        <property name="description" column="DESCRIPTION" type="java.lang.String" />
        <property name="address" column="ADDRESS" type="java.lang.String"/>
      </class>
    </hibernate-mapping>
    

    在表間共享 ID 值
    要點(diǎn)在于,在同一類層次結(jié)構(gòu)中映射的兩個(gè)表之間,不必共享相同的 ID 值。如果您進(jìn)行映射,那么 Hibernate 會(huì)為同一 ID 返回多個(gè)不同的對(duì)象。這可能會(huì)使 Hibernate 弄混 —— 您也會(huì)弄混。

    當(dāng)您查看清單 13 中的映射文件時(shí),您的第一個(gè)反應(yīng)可能是說:“呵!這個(gè)映射與我每天使用的沒什么不同啊!這里沒什么重要的東西!”而且您這么想應(yīng)當(dāng)是對(duì)的。實(shí)際上,第三個(gè)策略只需要一個(gè)條件:需要把 polymorphism 屬性設(shè)置為 implicit

    即使在映射文件中找不到 Estate 類,它仍然存在于類層次結(jié)構(gòu)之中。而且,因?yàn)閮蓚€(gè)映射的類( BuildingLand)是從 Estate 中繼承而來,所以我們可以在 HQL 查詢中使用這個(gè)抽象超類,如清單 14 所示。Hibernate 會(huì)用 內(nèi)省(introspection) 找到擴(kuò)展這個(gè)抽象類的類,以便依次為每個(gè)子類執(zhí)行對(duì)應(yīng)的 SQL 查詢。

    清單 14. find() 方法調(diào)用中的 HQL 查詢
    
    public Estate find(Integer id) {
      ...
      List objects =
        session.find(
          "select e from " + Estate.class.getName() + " as e where e.id = ?",
            new Object[] { id },
            new Type[] { Hibernate.INTEGER });
      ...
    }
    

    為了找到與指定 ID 匹配的 Estate,Hibernate 必須把清單 15 中的兩個(gè)查詢提交給數(shù)據(jù)庫。

    清單 15. SQL 查詢
    
    select land0_.ID as ID, land0_.DESCRIPTION as DESCRIPT2_, land0_.SQUARE_FEET as SQUARE_F3_ 
    from TB_LAND land0_ where (land0_.ID=? )
    
    select building0_.ID as ID, building0_.DESCRIPTION as DESCRIPT2_, building0_.ADDRESS as ADDRESS 
    from TB_BUILDING building0_ where (building0_.ID=? )
    

    正如我們?cè)诘诙€(gè)策略中看到的,在 RightEstate 類之間存在著 多對(duì)一 關(guān)系。在一般的表述中,這兩個(gè)表的關(guān)系可以這么表述:“一個(gè) Estate 可以指向 許多 Right。但是每個(gè) Right 只能指向 一個(gè) Estate。”但是從我們數(shù)據(jù)模型的角度來看,我們沒有一個(gè)惟一的表可以用來創(chuàng)建我們的外鍵約束,就像 TB_RIGHTTB_PERSON 之間那樣。這使得我們幾乎不可能創(chuàng)建外鍵。幸運(yùn)的是,Hibernate 為我們提供了一個(gè)非常強(qiáng)大的 XML 映射元素 —— <any> 標(biāo)簽,它的用法如清單 16 所示。

    清單 16. any 關(guān)系的 XML 映射
    
    <any name="estate"
    	meta-type="string"
    	id-type="java.lang.Integer">
      <meta-value value="LND" class="eg.hibernate.mapping.dataobject.Land"/>
      <meta-value value="BLD" class="eg.hibernate.mapping.dataobject.Building"/>
      <column name="REF_ESTATE_TYPE"/>
      <column name="REF_ESTATE_ID"/>          
    </any>
    

    禁止多態(tài)
    對(duì)于多態(tài)支持被禁止的類( <class...polymorphism="explicit"...>),如果針對(duì)它們的超類進(jìn)行查詢,會(huì)把它們排除在外。

    我們進(jìn)一步查看我們的新映射。我們的 虛擬外鍵 基于 TB_RIGHT 表的兩個(gè)列。第一個(gè)列( REF_ESTATE_TYPE)包含 discriminator 字符串,用這個(gè)字符串映射對(duì)應(yīng)的類名。第二個(gè)( REF_ESTATE_ID)是另外一個(gè)表的主鍵的列名。使用默認(rèn)設(shè)置時(shí),Hibernate 會(huì)在第一個(gè)列中保存映射的類名,這么做可能會(huì)非常消耗空間、沒有效率(特別是在代碼重構(gòu)修改類名的時(shí)候)。謝天謝地,Hibernate 還提供了一個(gè)用 <meta-value> XML 元素把類名映射到字符串約束的方法。這些約束的作用與在第二個(gè)策略中討論的 discriminator 的作用相同。再次聲明,這些特性只包含 Hibernate 和數(shù)據(jù)庫,所以不會(huì)改變類的層次結(jié)構(gòu)。

    數(shù)據(jù)庫模型的完整性
    雖然標(biāo)準(zhǔn) SQL 不允許對(duì)多個(gè)表同時(shí)針對(duì)指定列進(jìn)行參考約束,但是仍有可能添加觸發(fā)器,根據(jù)讀取的 discriminator 值,觸發(fā)器會(huì)檢測目錄中是否有數(shù)據(jù)。但是,這樣的 完整性實(shí)施 方法可能非常難以維護(hù),也有可能降低數(shù)據(jù)的整體性能。

    多態(tài) —— 用到極限!
    在使用 Hibernate 內(nèi)置的多態(tài)時(shí)需要記住一件事:如果您一不小心,把所有的類都用 polymorphism 屬性設(shè)置為 implicit,那么您檢索到的信息可能要比您想要的多得多。清單 17 顯示了一種使用兩個(gè)詞的 HQL 查詢來檢索 整個(gè)數(shù)據(jù)庫 的方法。

    清單 17. HQL 查詢
    
    public List all() {
      ...
      List objects = session.find("
            from Object");
      ...
    }
    
          

    該查詢的功能非常強(qiáng)大,您覺得呢?當(dāng)然,我們之中沒有多少人需要只用一個(gè) HQL 查詢檢索整個(gè)數(shù)據(jù)庫。這個(gè)(沒有實(shí)際意義)的示例的目的就是為了顯示隱式多態(tài)的能力。您可以利用這個(gè)能力避免把無用的、耗費(fèi)資源的 SQL 查詢發(fā)送到數(shù)據(jù)庫。

    結(jié)束語
    在本文中,我們?cè)噲D向您提供一個(gè)相當(dāng)簡單的實(shí)現(xiàn)示例,演示 Hibernate 提供的三個(gè)映射策略。回頭來看,每個(gè)策略都有自己的優(yōu)勢(shì)與不足:

    • 對(duì)于第一個(gè)策略(每個(gè)子類一個(gè)表),Hibernate 每次初始化和填充對(duì)象時(shí),會(huì)讀取多個(gè)表。如果您的索引定義得很好,而且層次結(jié)構(gòu)不是太深,那么這個(gè)操作可以產(chǎn)生良好的結(jié)果。但是,如果不是這種情況,那么您可能會(huì)遇到各種性能問題。

    • 對(duì)于第二個(gè)策略(每個(gè)類層次結(jié)構(gòu)一個(gè)表),您必須用 檢測約束 定義您自己的完整性。但隨著列的數(shù)量與時(shí)俱增,這個(gè)策略可能會(huì)變得難以維護(hù)。另一方面,您可能選擇根本不用這樣的約束,而依靠應(yīng)用程序的代碼來管理自己的數(shù)據(jù)完整性。

    • 第三個(gè)策略(每個(gè)具體類一個(gè)表)有一些映射限制,而底層數(shù)據(jù)模型不能使用參照完整性,這意味著您不能發(fā)揮關(guān)系數(shù)據(jù)庫引擎的所有潛力。但是,從好的方面說,該策略很常容易與另兩個(gè)策略組合在一起。

    不管您選擇哪種策略,都要記住,在整個(gè)過程當(dāng)中,無需修改 Java 類,這意味著業(yè)務(wù)對(duì)象與持續(xù)性框架之間一點(diǎn)聯(lián)系都沒有。正是這樣高水平的靈活性使 Hibernate 在對(duì)象關(guān)系 Java 項(xiàng)目中如此流行。

    參考資料

    • 您可以參閱本文在 developerWorks 全球站點(diǎn)上的 英文原文

    • 請(qǐng)單擊本文頂部或底部的 Code 圖標(biāo)下載本文中使用的源代碼示例。

    • Hibernate site 提供了您需要的與這個(gè)強(qiáng)大的對(duì)象持久性框架有關(guān)的所有信息。可以從這個(gè)站點(diǎn)下載運(yùn)行示例應(yīng)用程序所需的 Hibernate 文件。

    • HSQLDB 數(shù)據(jù)庫是一個(gè)開源的輕量級(jí)數(shù)據(jù)庫,完全用 Java 語言編寫。可以從這個(gè)站點(diǎn)下載 HSQLDB,并把它用作示例應(yīng)用程序的數(shù)據(jù)庫。

    • 請(qǐng)參閱 Hibernate 撰寫的 HQL reference,來獲得 Hibernate 查詢語言的完整文檔。

    • Using Hibernate to persist your Java objects to IBM DB2 Universal Database”,作者是 Javid Jamae 和 Kulvir Singh Bhogal(developerWorks,2003 年 6 月),該書提供了用 Hibernate 將類映射到數(shù)據(jù)庫表的良好指導(dǎo)。

    • 無需容器的對(duì)象關(guān)系映射 ”,作者是 Richard Hightower,(developerWorks,2004 年 4 月),它對(duì)使用 Hibernate 和 Spring 框架開發(fā)事務(wù)性持久性層進(jìn)行了介紹。

    • Developing Hibernate 應(yīng)用程序s for use with WebSphere Application Server”,作者 Sunil Patil( IBM WebSphere Developer Technical Journal, 2004 年 9 月),提供了創(chuàng)建 Hibernate 應(yīng)用程序時(shí)使用 Websphere Application Server 連接和事務(wù)管理的詳細(xì)指導(dǎo)。

    • Hibernate your data”,作者是 Davor Cengija(ONJava.com,2004 年 1 月),它提供了 Hibernate API 的所有基礎(chǔ)知識(shí),描述了如何利用 Hibernate API 的映射文件。

    • Hibernate in Action ,作者是 Christian Bauer 和 Gavin King(Independent Pub Group,2004 年),這是一份關(guān)于對(duì)象關(guān)系映射的理論與實(shí)踐指南。由 Hibernate 小組編寫。

    • Hibernate: A Developer's Notebook ,作者是 James Elliot(O'Reilly,2004 年),這是另一份 Hibernate 的精彩指南。

    • developerWorks Java 技術(shù)專區(qū) 中,可以找到數(shù)百篇有關(guān) Java 各個(gè)方面的技術(shù)文章。

    • 請(qǐng)?jiān)L問 Developer Bookstore,以獲得技術(shù)書籍的完整清單,其中包括數(shù)百本 Java 相關(guān)主題的書籍。

    下載
    Name Size Download method
    j-hibernate-source.zip FTP
    *關(guān)于下載方法的信息
    作者簡介
    作者照片Xavier Coulon 六年前以 IT 專家的身份加入 IBM 的法國分部,并開始從事各類平臺(tái)上的 ERP 咨詢工作。最近兩年,他一直在處理一個(gè)大型 J2EE 項(xiàng)目,這個(gè)項(xiàng)目包含諸如 Struts 和 Hibernate 之類的開源框架。您可以通過 xavier.coulon@fr.ibm.com 與 Xavier 聯(lián)系。


    作者照片Christian Brousseau 是一個(gè)了不起的加拿大人,他一直在開發(fā)軟件,有十多年的經(jīng)驗(yàn)。最初他做了大量 Windows 開發(fā)(C++、Visual Basic、MFC、ActiveX),后來,從 Java 語言的 1.0 版本起,他開始轉(zhuǎn)移到 Java 項(xiàng)目上。做 J2EE 顧問時(shí)積累的專業(yè)知識(shí)為他提供了一個(gè)去法國的好機(jī)會(huì),在法國,他協(xié)助設(shè)計(jì)、開發(fā)、部署了一些重要的企業(yè)級(jí) J2EE 項(xiàng)目。可以通過 cbrous@fr.ibm.com 與 Christian 聯(lián)系。



    posted on 2005-05-17 18:27 笨笨 閱讀(578) 評(píng)論(0)  編輯  收藏 所屬分類: J2EEHibernateAndSpringALL
    主站蜘蛛池模板: 国内精品免费麻豆网站91麻豆| 国产成人精品免费视频大全| 丁香婷婷亚洲六月综合色| 美女啪啪网站又黄又免费| 亚洲国产超清无码专区| 亚洲s色大片在线观看| 亚洲大尺度无码专区尤物| 国产V亚洲V天堂A无码| 亚洲国产成人一区二区精品区| 国产亚洲日韩在线三区| 亚洲色精品vr一区二区三区 | 亚洲高清乱码午夜电影网| 亚洲综合精品伊人久久| 亚洲另类无码一区二区三区| 久久亚洲精品成人无码| 免费一区二区三区在线视频| 一区二区三区在线观看免费 | 亚洲人成人网毛片在线播放| 亚洲日韩一中文字暮| 国产亚洲午夜精品| 一级毛片大全免费播放| 国产婷婷成人久久Av免费高清| 99久9在线|免费| 成人无码区免费A片视频WWW| 狼友av永久网站免费观看| 全黄性性激高免费视频| 亚洲日韩精品一区二区三区无码 | 国产男女猛烈无遮挡免费网站| 亚洲精品国产精品乱码不卡 | 免费看美女让人桶尿口| 亚洲午夜爱爱香蕉片| 亚洲成人在线电影| 中文字幕无码精品亚洲资源网久久| 青草久久精品亚洲综合专区| aa级女人大片喷水视频免费| 84pao强力永久免费高清| 国内大片在线免费看| 国产亚洲美女精品久久久久狼| 亚洲天堂电影在线观看| 四虎影视久久久免费观看| 亚洲a一级免费视频|