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

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

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

    【永恒的瞬間】
    ?Give me hapy ?

    第 3 章 體系結構(Architecture)

    3.1. 概況(Overview)

    一個非常簡要的Hibernate體系結構的概要圖:

    這個圖可以看出,Hibernater使用數據庫和配置信息來為應用程序提供持久化服務(以及持久的對象)。

    我們來更詳細地看一下Hibernate運行時體系結構。由于Hibernate非常靈活,且支持數種應用方案, 所以我們這只描述一下兩種極端的情況。“輕型”的體系結構方案,要求應用程序提供自己的JDBC 連接并管理自己的事務。這種方案使用了Hibernate API的最小子集:

    “全面解決”的體系結構方案,將應用層從底層的JDBC/JTA API中抽象出來,而讓Hibernate來處理這些細節。
    圖中各個對象的定義如下:
    SessionFactory (org.hibernate.SessionFactory)

    針對單個數據庫映射關系經過編譯后的內存鏡像,它也是線程安全的(不可變)。 它是生成Session的工廠,本身要用到ConnectionProvider。 該對象可以在進程或集群的級別上,為那些事務之間可以重用的數據提供可選的二級緩存。

    Session (org.hibernate.Session)

    表示應用程序與持久儲存層之間交互操作的一個單線程對象,此對象生存期很短。 其隱藏了JDBC連接,也是Transaction的工廠。 其會持有一個針對持久化對象的必選(第一級)緩存,在遍歷對象圖或者根據持久化標識查找對象時會用到。

    持久的對象及其集合

    帶有持久化狀態的、具有業務功能的單線程對象,此對象生存期很短。 這些對象可以是普通的JavaBeans/POJO,唯一特殊的是他們正與(僅僅一個)Session相關聯。 這個Session被關閉的同時,這些對象也會脫離持久化狀態,可以被應用程序的任何層自由使用。 (例如,用作跟表示層打交道的數據傳輸對象data transfer object。)

    瞬態(transient)以及脫管(detached)的對象及其集合

    持久類的沒有與Session相關聯的實例。 他們可能是在被應用程序實例化后,尚未進行持久化的對象。 也可能是因為實例化他們的Session已經被關閉而脫離持久化的對象。

    事務Transaction (org.hibernate.Transaction)

    (可選的)應用程序用來指定原子操作單元范圍的對象,它是單線程的,生存期很短。 它通過抽象將應用從底層具體的JDBC、JTA以及CORBA事務隔離開。 某些情況下,一個Session之內可能包含多個Transaction對象。 盡管是否使用該對象是可選的,但是事務邊界的開啟與關閉(無論是使用底層的API還是使用Transaction對象)是必不可少的。

    ConnectionProvider (org.hibernate.connection.ConnectionProvider)

    (可選的)生成JDBC連接的工廠(同時也起到連接池的作用)。 它通過抽象將應用從底層的DatasourceDriverManager隔離開。 僅供開發者擴展/實現用,并不暴露給應用程序使用。

    TransactionFactory (org.hibernate.TransactionFactory)

    (可選的)生成Transaction對象實例的工廠。 僅供開發者擴展/實現用,并不暴露給應用程序使用。

    擴展接口

    Hibernate提供了很多可選的擴展接口,你可以通過實現它們來定制你的持久層的行為。 具體請參考API文檔。

     

    在一個“輕型”的體系結構中,應用程序可能繞過 Transaction/TransactionFactory 以及 ConnectionProvider 等API直接跟JTA或JDBC打交道。

    3.2. 實例狀態

    一個持久化類的實例可能處于三種不同狀態中的某一種。 這三種狀態的定義則與所謂的持久化上下文(persistence context)有關。 Hibernate的Session對象就是這個所謂的持久化上下文:

    瞬態(transient)

    該實例從未與任何持久化上下文關聯過。它沒有持久化標識(相當于主鍵)。

    持久(persistent)

    實例目前與某個持久化上下文有關聯。 它擁有持久化標識(相當于主鍵),并且可能在數據庫中有一個對應的行。 對于某一個特定的持久化上下文,Hibernate保證持久化標識與Java標識(其值代表對象在內存中的位置)等價。

    脫管(detached)

    實例曾經與某個持久化上下文發生過關聯,不過那個上下文被關閉了, 或者這個實例是被序列化(serialize)到這個進程來的。 它擁有持久化標識,并且在數據庫中可能存在一個對應的行。 對于脫管狀態的實例,Hibernate不保證任何持久化標識和Java標識的關系。

    3.3. JMX整合

    JMX是管理Java組件(Java components)的J2EE規范。 Hibernate 可以通過一個JMX標準服務來管理。 在這個發行版本中,我們提供了一個MBean接口的實現,即 org.hibernate.jmx.HibernateService

    想要看如何在JBoss應用服務器上將Hibernate部署為一個JMX服務的例子,您可以參考JBoss用戶指南。 我們現在說一下在Jboss應用服務器上,使用JMX來部署Hibernate的好處:

    • Session管理: Hibernate的Session對象的生命周期可以 自動跟一個JTA事務邊界綁定。這意味著你無需手工開關Session了, 這項 工作會由JBoss EJB 攔截器來完成。你再也不用擔心你的代碼中的事務邊界了(除非你想利用Hibernate提供 的Transaction API來自己寫一個便于移植的的持久層)。 你現在要通過 HibernateContext來操作Session了。

    • HAR 部署: 通常情況下,你會使用JBoss的服務部署描述符(在EAR或/和SAR文件中)來部署Hibernate JMX服務。 這種部署方式支持所有常見的Hibernate SessionFactory的配置選項。 不過,你需在部署描述符中,列出你所有的映射文件的名字。如果你使用HAR部署方式, JBoss 會自動探測出你的HAR文件中所有的映射文件。

    這些選項更多的描述,請參考JBoss 應用程序用戶指南。

    將Hibernate以部署為JMX服務的另一個好處,是可以查看Hibernate的運行時統計信息。參看 第 4.4.6 節 “ Hibernate的統計(statistics)機制 ”.

    3.4. 對JCA的支持

    Hibernate也可以被配置為一個JCA連接器(JCA connector)。更多信息請參看網站。 請注意,Hibernate對JCA的支持,仍處于實驗性質。

    第 5 章 持久化類(Persistent Classes)

    在應用程序中,用來實現業務問題實體的(如,在電子商務應用程序中的Customer和Order) 類就是持久化類。不能認為所有的持久化類的實例都是持久的狀態——一個實例的狀態也可能 是瞬時的或脫管的。

    如果這些持久化類遵循一些簡單的規則,Hibernate能夠工作得最好,這些規則被稱作, 簡單傳統Java對象(POJO:Plain Old Java Object)編程模型。但是這些規則沒有一個是必需的。 實際上,Hibernate3對于你的持久化類幾乎不做任何設想。你可以用其他的方法來表達領域模型: 比如,使用Map實例的樹型結構。

    5.1. 一個簡單的POJO例子

    大多數Java程序需要用一個持久化類來表示貓科動物。

    package eg;
    import java.util.Set;
    import java.util.Date;
    public class Cat {
    private Long id; // identifier
    private Date birthdate;
    private Color color;
    private char sex;
    private float weight;
    private int litterId;
    private Cat mother;
    private Set kittens = new HashSet();
    private void setId(Long id) {
    this.id=id;
    }
    public Long getId() {
    return id;
    }
    void setBirthdate(Date date) {
    birthdate = date;
    }
    public Date getBirthdate() {
    return birthdate;
    }
    void setWeight(float weight) {
    this.weight = weight;
    }
    public float getWeight() {
    return weight;
    }
    public Color getColor() {
    return color;
    }
    void setColor(Color color) {
    this.color = color;
    }
    void setSex(char sex) {
    this.sex=sex;
    }
    public char getSex() {
    return sex;
    }
    void setLitterId(int id) {
    this.litterId = id;
    }
    public int getLitterId() {
    return litterId;
    }
    void setMother(Cat mother) {
    this.mother = mother;
    }
    public Cat getMother() {
    return mother;
    }
    void setKittens(Set kittens) {
    this.kittens = kittens;
    }
    public Set getKittens() {
    return kittens;
    }
    // addKitten not needed by Hibernate
    public void addKitten(Cat kitten) {
    kitten.setMother(this);
    kitten.setLitterId( kittens.size() );
    kittens.add(kitten);
    }
    }

    這里要遵循四條主要的規則:

    5.1.1. 為持久化字段聲明訪問器(accessors)和是否可變的標志(mutators)

    Cat為它的所有持久化字段聲明了訪問方法。很多其他ORM工具直接對 實例變量進行持久化。我們相信從持久化機制中分離這種實現細節要好得多。 Hibernate持久化JavaBeans風格的屬性,認可如下形式的方法名: getFoo, isFoosetFoo。 如果需要,你總是可以切換特定的屬性的指示字段的訪問方法。

    屬性不需要要聲明為public的。Hibernate默認使用 protectedprivate的get/set方法對, 對屬性進行持久化。

    5.1.2. 實現一個默認的(即無參數的)構造方法(constructor)

    Cat有一個無參數的構造方法。所有的持久化類都必須有一個 默認的構造方法(可以不是public的),這樣的話Hibernate就可以使用 Constructor.newInstance()來實例化它們。 我們建議,在Hibernate中,為了運行期代理的生成,構造方法至少是 包(package)內可見的。

    5.1.3. 提供一個標識屬性(identifier property)(可選)

    Cat有一個屬性叫做id。這個屬性映射數據庫表的主 鍵字段。這個屬性可以叫任何名字,其類型可以是任何的原始類型、原始類型的包裝類型、 java.lang.String 或者是 java.util.Date。 (如果你的老式數據庫表有聯合主鍵,你甚至可以用一個用戶自定義的類,該類擁有這些類型 的屬性。參見后面的關于聯合標識符的章節。)

    標識符屬性是可選的。可以不用管它,讓Hibernate內部來追蹤對象的識別。 不推薦使用這個屬性。

    實際上,一些功能只對那些聲明了標識符屬性的類起作用:

    我們建議你對持久化類聲明命名一致的標識屬性。我們還建議你使用一 個可以為空(也就是說,不是原始類型)的類型。

    5.1.4. 使用非final的類 (可選)

    代理(proxies)是Hibernate的一個重要的功能,它依賴的條件是,持久 化類或者是非final的,或者是實現了一個所有方法都聲明為public的接口。

    你可以用Hibernate持久化一個沒有實現任何接口的final類,但是你 不能使用代理來延遲關聯加載,這會限制你進行性能優化的選擇。

    你也應該避免在非final類中聲明 public final的方法。如果你想使用一 個有public final方法的類,你必須通過設置lazy="false" 來明確的禁用代理。

    5.2. 實現繼承(Inheritance)

    子類也必須遵守第一條和第二條規則。它從超類Cat繼承了標識屬性。

    package eg;
    public class DomesticCat extends Cat {
    private String name;
    public String getName() {
    return name;
    }
    protected void setName(String name) {
    this.name=name;
    }
    }

    5.3. 實現equals()hashCode()

    如果你有如下需求,你必須重載 equals()hashCode()方法:

    • 想把持久類的實例放入Set中(當表示多值關聯時,推薦這么做)

    • 想重用脫管實例

    Hibernate保證,持久化標識(數據庫的行)和僅在特定會話范圍內的Java標識是等值的。因此,一旦 我們混合了從不同會話中獲取的實例,如果我們希望Set有明確的語義,我們必 須實現equals()hashCode()

    實現equals()/hashCode()最顯而易見的方法是比較兩個對象 標識符的值。如果值相同,則兩個對象對應于數據庫的同一行,因此它們是相等的(如果都被添加到 Set,則在Set中只有一個元素)。不幸的是,對生成的標識不能 使用這種方法。Hibernate僅對那些持久化對象賦標識值,一個新創建的實例將不會有任何標識值。此外, 如果一個實例沒有被保存(unsaved),并且在一個Set中,保存它將會給這個對象 賦一個標識值。如果equals()hashCode()是基于標識值 實現的,則其哈希碼將會改變,違反Set的契約。建議去Hibernate的站點看關于這個 問題的全部討論。注意,這不是一個Hibernate問題,而是一般的Java對象標識和相等的語義問題。

    我們建議使用業務鍵值相等(Business key equality)來實現equals()hashCode()。業務鍵值相等的意思是,equals()方法 僅僅比較來自業務鍵的屬性,一個業務鍵將標識在真實世界里(一個天生的候選鍵) 的實例。

    public class Cat {
    ...
    public boolean equals(Object other) {
    if (this == other) return true;
    if ( !(other instanceof Cat) ) return false;
    final Cat cat = (Cat) other;
    if ( !cat.getLitterId().equals( getLitterId() ) ) return false;
    if ( !cat.getMother().equals( getMother() ) ) return false;
    return true;
    }
    public int hashCode() {
    int result;
    result = getMother().hashCode();
    result = 29 * result + getLitterId();
    return result;
    }
    }

    注意,業務鍵不必是象數據庫的主鍵那樣是固定不變的(參見第 12.1.3 節 “關注對象標識(Considering object identity)”)。 對業務鍵而言,不可變或唯一的屬性是好的候選。

    5.4. 動態模型(Dynamic models)

    注意,以下特性在當前是基于實驗考慮的,可能會在將來改變。

    運行期的持久化實體沒有必要象POJO類或JavaBean對象一樣表示。Hibernate也支持動態模型 (在運行期使用MapMap)和象DOM4J的樹模型那 樣的實體表示。使用這種方法,你不用寫持久化類,只寫映射文件就行了。

    Hibernate默認工作在普通POJO模式。你可以使用配置選項default_entity_mode, 對特定的SessionFactory,設置一個默認的實體表示模式。 (參見表 4.3 “ Hibernate配置屬性 ”。)

    下面是用Map來表示的例子。首先,在映射文件中,要聲明 entity-name來代替(或外加)一個類名。

    <hibernate-mapping>
    <class entity-name="Customer">
    <id name="id"
    type="long"
    column="ID">
    <generator class="sequence"/>
    </id>
    <property name="name"
    column="NAME"
    type="string"/>
    <property name="address"
    column="ADDRESS"
    type="string"/>
    <many-to-one name="organization"
    column="ORGANIZATION_ID"
    class="Organization"/>
    <bag name="orders"
    inverse="true"
    lazy="false"
    cascade="all">
    <key column="CUSTOMER_ID"/>
    <one-to-many class="Order"/>
    </bag>
    </class>
    </hibernate-mapping>

    注意,雖然是用目標類名來聲明關聯的,但是關聯的目標類型除了是POJO之外,也可以 是一個動態的實體。

    在使用dynamic-mapSessionFactory 設置了默認的實體模式之后,可以在運行期使用MapMap

    Session s = openSession();
    Transaction tx = s.beginTransaction();
    Session s = openSession();
    // Create a customer
    Map david = new HashMap();
    david.put("name", "David");
    // Create an organization
    Map foobar = new HashMap();
    foobar.put("name", "Foobar Inc.");
    // Link both
    david.put("organization", foobar);
    // Save both
    s.save("Customer", david);
    s.save("Organization", foobar);
    tx.commit();
    s.close();

    動態映射的好處是,使原型在不需要實體類實現的情況下,快速轉變時間。然而,你無法進行 編譯期的類型檢查,并可能由此會處理很多的運行期異常。幸虧有了Hibernate映射,它使得數 據庫的schema能容易的規格化和合理化,并允許稍后添加正確的領域模型的最新實現。

    實體表示模式也能在每個Session的基礎上設置:

    Session dynamicSession = pojoSession.getSession(EntityMode.MAP);
    // Create a customer
    Map david = new HashMap();
    david.put("name", "David");
    dynamicSession.save("Customer", david);
    ...
    dynamicSession.flush();
    dynamicSession.close()
    ...
    // Continue on pojoSession
    

    請注意,用EntityMode調用getSession()是在 Session的API中,而不是SessionFactory。 這樣,新的Session共享底層的JDBC連接,事務,和其他的上下文信 息。這意味著,你不需要在第二個Session中調用 flush()close(),同樣的,把事務和連接的處理 交給原來的工作單元。

    關于XML表示能力的更多信息可以在第 19 章 XML映射中找到。

    TODO:在property和proxy的包里,用戶擴展文件框架。

    posted on 2007-05-15 16:04 ???MengChuChen 閱讀(2216) 評論(0)  編輯  收藏 所屬分類: hibernate
    主站蜘蛛池模板: 亚洲AV日韩综合一区| 亚洲在成人网在线看| 一区二区三区免费电影| 国产午夜鲁丝片AV无码免费| 亚洲成av人片天堂网无码】| 免费看国产成年无码AV片| 亚洲高清美女一区二区三区| 91精品免费久久久久久久久| 日韩亚洲国产综合高清| 天天摸夜夜摸成人免费视频| 国产成人综合亚洲| 久久久久亚洲AV成人网人人网站| 国产成人无码免费看片软件| 亚洲中文字幕在线第六区| 免费播放一区二区三区| 亚洲91精品麻豆国产系列在线| 成人免费视频软件网站| 国产成人亚洲综合a∨| 亚洲伊人久久综合影院| 国产免费一区二区三区在线观看| 久久亚洲精品国产精品| 国产无人区码卡二卡三卡免费 | 国产精品成人免费一区二区 | 国产免费久久久久久无码| 亚洲国产精品VA在线观看麻豆 | 亚洲fuli在线观看| 永久免费无码网站在线观看| 高清免费久久午夜精品| 亚洲今日精彩视频| 日韩毛片免费在线观看| 中文在线免费看视频| 亚洲国产日韩在线一区| 亚洲片一区二区三区| 在线人成精品免费视频| 亚洲av无码专区亚洲av不卡| 亚洲精品国产字幕久久不卡| 成人男女网18免费视频| 成人免费区一区二区三区| 亚洲色欲色欱wwW在线| 日韩亚洲人成在线综合日本| 免费无码成人AV片在线在线播放|