kapok

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

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

          內容:
          概述
          我們的支持示例
          策略 1: 每個子類一個表(Persons)
          策略 2:每個類層次結構一個表(Rights)
          數據庫模型的完整性
          策略 3: 每個具體類一個表(Estates)
          多態 —— 用到極限!
          結束語
          參考資料
          下載
          作者簡介
          對本文的評價
          相關內容:
          無需容器的對象關系映射
          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 時事通訊
          學習映射類層次結構的三個易于實現的策略

          級別: 初級

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

          2005 年 1 月 14 日

          Hibernate 是一個對象關系映射和持久性框架,它提供了許多高級特性,從內省到多態和繼承映射。但是,把類的層次結構映射到關系數據庫模型,可能會比較困難。本文將介紹三個策略,在日常的編程之中您可以用它們把復雜的對象模型容易地映射到關系數據庫模型。

          概述
          Hibernate 是一個純 Java 的對象關系映射和持久性框架,它允許您用 XML 配置文件把普通 Java 對象映射到關系數據庫表。使用 Hibernate 能夠節約大量項目開發時間,因為整個 JDBC 層都由這個框架管理。這意味著您的應用程序的數據訪問層位于 Hibernate 之上,完全是從底層數據模型中抽象出來的。

          比起其他類似的對象關系映射技術(JDO、實體 bean、內部開發等),Hibernate 有許多優勢:它是免費的、開源的,已經成熟到良好的程度,并得到廣泛應用,而且還有一個非常活躍的社區論壇。

          要把 Hibernate 集成到現有的 Java 項目,則需要執行以下步驟:

          1. 從 Hibernate 的 Web 站點下載 Hibernate 框架的最新發行版(請參閱 參考資料一節中的鏈接。)

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

          3. 創建 XML 配置文件,用它把 Java 對象映射到數據庫表。(我們將在本文中描述這個過程。)

          4. 把 XML 配置文件復制到應用程序的 CLASSPATH。

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

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

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

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

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

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

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

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

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

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

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

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

          從這個抽象出發,我們可以開發圖 1 所示的類模型:

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

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

          圖 2 顯示了這個數據模型:

          圖 2. 完整的數據模型
          完整的數據模型

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

          設置 Java 項目
          雖然您總能用命令行構建并執行示例代碼,但是您可能想在 IDE 中設置項目,以便更好地進行集成。在示例代碼包里,您可以找到以下目錄:

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

          • data,包含 HSQLDB 使用的配置文件。您還可以找到一個叫作 startHSQLDB.bat 的批處理文件,您可以用它啟動數據庫。

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

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

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

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

          在清單 2 所示的 XML 映射文件中,您會注意到,在 Person 的映射定義中,聲明了兩個具體的 <joined-subclass> 類。XML 元素 <id> 映射到頂級表 TB_PERSON 的主鍵,同時 <key> 元素(來自每個子類)映射到 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 的一個新實例,形成我們使用 Hibernate 的 Java 代碼非常容易,如清單 3 所示:

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

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

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

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

          清單 5. 調用 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 會自動執行 SQL 的 JOIN,從兩個表中檢索所有必要信息,如清單 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=? )
          
                

          查詢抽象類
          當查詢抽象類時,Hibernate 會自動返回一個集合,由匹配的具體異構子類構成。例如,如果我們查詢數據庫中的每個 Person,Hibernate 會返回一列 IndividualCorporation 對象。

          但是,當沒有指定具體類時,Hibernate 需要執行 SQL 的 JOIN,因為它不知道要查詢哪個表。在 HQL 查詢返回的檢索到的所有表的列中,還會返回一個額外的 dynamic 列。Hibernate 使用 clazz 列來初始化和填充返回的對象。我們把這個類叫作決定因子(determination dynamic),與我們在第二個策略中使用的方法相對。

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

          清單 7. find() 方法調用中的 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:每個類層次結構一個表(Rights)
          對于我們的 Right 層次結構,我們只使用一個表( TB_RIGHT)來保存整體類層次結構。您會注意到, TB_RIGHT 表擁有保存 Right 類層次結構的每個屬性所需要的所有列。保存的實例值也就會保存在表中,每個沒有使用的列則用 NULL 值填充。(因為它到處都是“洞”,所以我們經常把它叫作 瑞士奶酪表

          在圖 3 中,您會注意到, TB_RIGHT 表中包含一個額外的列 DISCRIMINATOR。Hibernate 用這個列自動初始化對應的類并相應進行填充。這個類用映射文件中的 XML 元素 <discriminator> 進行映射。

          圖 3. TB_RIGHT 表的內容
          TB_RIGHT 表的內容

          簡明性技巧
          在每個大型項目中,您都會面臨包含多級抽象類的復雜的類層次結構。幸運的是,您不必指定抽象類的 discriminator-value,只需為 Hibernate 實際要使用的具體類指定這個值即可。

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

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

          清單 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 的映射文件中,您會注意到 RightPerson 層次結構之間的“多對一”關系,它(實質上)與 Person 層次結構(一對多)的關系正好相反。還請注意 RightEstate 層次結構之間的關系;稍后我們將在本文中介紹這層關系。

          使用第一個策略時,Hibernate 在訪問數據庫時生成了非常有效的 SQL 語句。當我們查詢具體類時,如清單 10 所示,會在 discriminator 的 Hibernate 過濾器上自動取值 —— 這是件好事,因為這意味著 Hibernate 只讀取與指定類對應的列。

          清單 10. 針對具體類的 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'
          

          當我們查詢抽象類時,事情變得有些復雜。因為 Hibernate 不知道您要查詢哪個特定的類,所以必須讀取每個列(包括 discriminator 類),然后才能決定要初始化哪個類,最后再填充它。接下來,discriminator 充當的角色與第一個策略中 clazz 列充當的角色相同。但是這個方法顯然更死板,因為類名直接派生自 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 定義,本文中描述的前兩個策略是相互排斥的,這意味著它們無法組合在一起,映射同一個層次結構。

          數據庫模型的完整性
          關于第二個策略,有一個需要重點考慮的地方:為了讓它工作,必須把所有非共享列設置為 NULLABLE。因為開發人員通常會依賴數據庫的約束,所以生成的表可能非常難以處理。(畢竟,把有持續時間的 Lease 設置為 NULL 沒多大意義!)

          解決方案之一是用 數據庫級檢測約束。您可以根據 DISCRIMINATOR 的值,定義一套要實施的規則,如清單 12 所示。當然,數據庫引擎必須支持這些特性。而且,由于必須同時為全部具體類用一個有效表達式表示這些約束,所以當層次結構發展的時候,維護會很困難。

          清單 12. 數據完整性約束
          
          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: 每個具體類一個表(Estates)
          我們的第三個,也是最后一個策略可能是三個策略當中最有想象力的:每個具體類一個表,抽象超類 Estate 沒有表。我們依靠 Hibernate 提供對 多態(polymorphism)的支持。在清單 3 所示的 XML 映射文件中,您會注意到,其中只映射了兩個具體類( 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 值
          要點在于,在同一類層次結構中映射的兩個表之間,不必共享相同的 ID 值。如果您進行映射,那么 Hibernate 會為同一 ID 返回多個不同的對象。這可能會使 Hibernate 弄混 —— 您也會弄混。

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

          即使在映射文件中找不到 Estate 類,它仍然存在于類層次結構之中。而且,因為兩個映射的類( BuildingLand)是從 Estate 中繼承而來,所以我們可以在 HQL 查詢中使用這個抽象超類,如清單 14 所示。Hibernate 會用 內省(introspection) 找到擴展這個抽象類的類,以便依次為每個子類執行對應的 SQL 查詢。

          清單 14. find() 方法調用中的 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 中的兩個查詢提交給數據庫。

          清單 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=? )
          

          正如我們在第二個策略中看到的,在 RightEstate 類之間存在著 多對一 關系。在一般的表述中,這兩個表的關系可以這么表述:“一個 Estate 可以指向 許多 Right。但是每個 Right 只能指向 一個 Estate。”但是從我們數據模型的角度來看,我們沒有一個惟一的表可以用來創建我們的外鍵約束,就像 TB_RIGHTTB_PERSON 之間那樣。這使得我們幾乎不可能創建外鍵。幸運的是,Hibernate 為我們提供了一個非常強大的 XML 映射元素 —— <any> 標簽,它的用法如清單 16 所示。

          清單 16. any 關系的 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>
          

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

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

          數據庫模型的完整性
          雖然標準 SQL 不允許對多個表同時針對指定列進行參考約束,但是仍有可能添加觸發器,根據讀取的 discriminator 值,觸發器會檢測目錄中是否有數據。但是,這樣的 完整性實施 方法可能非常難以維護,也有可能降低數據的整體性能。

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

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

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

          結束語
          在本文中,我們試圖向您提供一個相當簡單的實現示例,演示 Hibernate 提供的三個映射策略。回頭來看,每個策略都有自己的優勢與不足:

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

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

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

          不管您選擇哪種策略,都要記住,在整個過程當中,無需修改 Java 類,這意味著業務對象與持續性框架之間一點聯系都沒有。正是這樣高水平的靈活性使 Hibernate 在對象關系 Java 項目中如此流行。

          參考資料

          • 您可以參閱本文在 developerWorks 全球站點上的 英文原文

          • 請單擊本文頂部或底部的 Code 圖標下載本文中使用的源代碼示例。

          • Hibernate site 提供了您需要的與這個強大的對象持久性框架有關的所有信息。可以從這個站點下載運行示例應用程序所需的 Hibernate 文件。

          • HSQLDB 數據庫是一個開源的輕量級數據庫,完全用 Java 語言編寫。可以從這個站點下載 HSQLDB,并把它用作示例應用程序的數據庫。

          • 請參閱 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 將類映射到數據庫表的良好指導。

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

          • Developing Hibernate 應用程序s for use with WebSphere Application Server”,作者 Sunil Patil( IBM WebSphere Developer Technical Journal, 2004 年 9 月),提供了創建 Hibernate 應用程序時使用 Websphere Application Server 連接和事務管理的詳細指導。

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

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

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

          • developerWorks Java 技術專區 中,可以找到數百篇有關 Java 各個方面的技術文章。

          • 請訪問 Developer Bookstore,以獲得技術書籍的完整清單,其中包括數百本 Java 相關主題的書籍。

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


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



          posted on 2005-05-17 18:27 笨笨 閱讀(580) 評論(0)  編輯  收藏 所屬分類: J2EEHibernateAndSpringALL
          主站蜘蛛池模板: 阳曲县| 新竹县| 乌苏市| 阿图什市| 广州市| 改则县| 阿城市| 武平县| 沙坪坝区| 米易县| 荥阳市| 岳西县| 邳州市| 临江市| 陵川县| 宁夏| 洪洞县| 大名县| 报价| 永川市| 通河县| 清徐县| 广东省| 泰州市| 库尔勒市| 青州市| 清涧县| 西峡县| 岗巴县| 沙田区| 邵阳县| 疏附县| 房山区| 集安市| 永新县| 平果县| 浪卡子县| 仁怀市| 固原市| 民勤县| 博湖县|