第七色在线视频,2021少妇久久久久久久久久,亚洲欧洲精品成人久久av18,亚洲国产精品特色大片观看完整版,孙宇晨将参加特朗普的晚宴

Hibernate 一對一關聯映射

1. 前言

本節(jié)課程和大家一起聊聊關聯映射。通過本節(jié)課程的學習,你將了解到:

  • 什么是關聯映射;
  • 如何實現一對一關聯映射。

2. 關聯映射

關系數據庫中的數據以表為家,一張表一個家,一個家住一類數據。眾多表組成關系型社區(qū),關系型社區(qū)群體中的數據關系通過主外鍵方式描述。

表與表之間的數據根據彼此的關系可分為:

  • 一對一關系: 如老公表和老婆表的關系;
  • 一對多關系: 如用戶表和銀行賬號表關系;
  • 多對一關系: 如銀行帳號表對用戶表關系;
  • 多對多關系: 如學生表和課程表關系。

不管是哪種關系,都可以通過主外鍵方式聯系。
一對多、多對一本質一樣,正如一塊硬幣的正反面,看待同一個事物的角度不同。
多對多通過中間表的方式拆分成兩個一對多(多對一)。

以上都是關系型數據庫中的基礎知識,美好的回憶有助于鞏固。

開發(fā)者使用 Hibernate 操作某一張表中的數據時,有 2 件事情要做:

  • 在程序中構建一個與表結構相似的類(這個類可稱為實體 [entity] 類);
  • 使用注解或 XML 語法把類結構表結構關聯映射起來(此時這個類可稱為 PO)。

有了 PO,Hibernate 就能在程序和數據庫之間進行數據貿易往來。

2.1 新的需求總是接踵而至

如果程序要求 Hibernate 操作多張表中的數據,并要求把獲取的數據封裝到對象中,又如何操作?

程序說:親愛的 Hibernate,幫我查詢一下學生信息和學生的家庭地址信息。

差點忘記告訴你:學生信息學生的家庭地址信息分別存放在兩張表中,且一名學生只能有一個地址。

這是假設,所以請不要糾結這種假設。

Hibernate 說: 可以。但有幾件事情必須按要求做好,否則干不了。

  1. 首先須確定數據庫中存在學生表和地址表,并確定兩者關系。使用地址編號 addressId 字段作共同字段,addressId 在地址表中是主鍵,在學生表中是外鍵。

圖片描述

  1. 回到程序,構建兩個類:Student 類、Address 類,添加注解描述。分別映射學生表、地址表。
    Hibernate 說:還不夠。

數據庫中的表之間是有關系的,這種關系在 Student 類Address 類 中也必須體現出來。
這也是 Hibernate 能查詢到多表中數據的核心要求。

2.2 PO 之間映射表之間的關系

從編碼層面上講,就是如何在 Student 類Address 類 之間體現出數據庫表中數據之間的關系

先從 Student 類 中開始,在 Student 類 中添加一個屬性字段。

private Address address;

address 屬性是一個 Address 類類型,數據庫不認得這玩意兒,Hibernate 表示開始要一個頭兩個大了,眩暈啦。

null 你先進入學生表,然后根據學生表中的 addressId 進入到地址表,找到對應數據。

Hibernate 又沒有讀心術,它如何知道你心里所想。

所以,需要通過 XML注解語法把開發(fā)者的想法告訴 Hibernate

private Address address;
@OneToOne(targetEntity = Address.class)
@JoinColumn(name = "addressId")
public Address getAddress() {
return address;
}
  • @OneToOne 注解告訴 Hibernateaddress 屬性的值要麻煩您先找到 學生表 addressId,再辛苦去一下 地址表,把對應的地址信息查詢出來;

  • @JoinColumn:告訴 Hibernate 帶著 addressId 到地址表中查找。

主配置文件中添加如下信息:

<property name=*"hbm2ddl.auto"*>create</property>
<mapping class=*"com.mk.po.Student"* />
<mapping class=*"com.mk.po.Address"* />

Hibernate 創(chuàng)建完畢后,添加幾條測試數據,操作完成后別忘記改回來。

此處操作自動完成!相信聰明如你,一定沒問題。

<property name="hbm2ddl.auto">update</property>

圖片描述

2.3 測試時間

查詢學生及學生的地址信息:

try {
    transaction = session.beginTransaction();
    Student stu = (Student) session.get(Student.class, new Integer(1));
    System.out.println("----------------學生信息---------------");
    System.out.println("學生姓名:" + stu.getStuName());
    System.out.println("-----------------地址信息-----------------");
    System.out.println("學生家庭地址:"+stu.getAddress().getAddressName());
    transaction.commit();
} catch (Exception e) {
    transaction.rollback();
} finally {
    session.close();
}

輸出結果:

Hibernate: 
    select
        student0_.stuId as stuId1_1_1_,
        student0_.addressId as addressI6_1_1_,
        student0_.stuName as stuName2_1_1_,
        student0_.stuPassword as stuPassw3_1_1_,
        student0_.stuPic as stuPic4_1_1_,
        student0_.stuSex as stuSex5_1_1_,
        address1_.addressId as addressI1_0_0_,
        address1_.addressName as addressN2_0_0_,
        address1_.descript as descript3_0_0_ 
    from
        Student student0_ 
    left outer join
        Address address1_ 
            on student0_.addressId=address1_.addressId 
    where
        student0_.stuId=?
----------------學生信息---------------
學生姓名:Hibernate老大
-----------------地址信息-----------------
學生家庭地址:北京

Hibernate 使用 left outer join 構 建一條 Sql 語句,一次性訪問 2 張表,同時獲取了學生信息和地址信息;

請問 Hibernate,你能不能查詢地址信息時,查詢出地址是哪個學生的。

可以,但是,需要在地址類中添加如下代碼:

private Student student;
@OneToOne(targetEntity=Student.class,mappedBy="address")
public Student getStudent() {
	return student;
}
  • @OneToOne 注解的 targetEntity=Student.class 告訴 Hibernate,此屬性的值對應的是學生表中的數據;

  • Student 類已經使用了 @OneToOne 映射。mappedBy=“address” 意思是說:Hibernate!student 類中已經說明的夠清楚了吧,這里就不要我再啰嗦了。

測試實例:

try {
    transaction = session.beginTransaction();
	Address address = (Address) session.get(Address.class, new Integer(1));
	System.out.println("----------------地址信息---------------");
	System.out.println("地址信息:" + address.getAddressName());
	System.out.println("-----------------學生信息-----------------");
	System.out.println("學生姓名:" + address.getStudent().getStuName());
	transaction.commit();
} catch (Exception e) {
	transaction.rollback();
} finally {
	session.close();
}

輸出結果:Hibernate 自動構建了多表查詢語句,一次性從數據庫獲取所有數據。

Hibernate: 
    select
        address0_.addressId as addressI1_0_1_,
        address0_.addressName as addressN2_0_1_,
        address0_.descript as descript3_0_1_,
        student1_.stuId as stuId1_1_0_,
        student1_.addressId as addressI6_1_0_,
        student1_.stuName as stuName2_1_0_,
        student1_.stuPassword as stuPassw3_1_0_,
        student1_.stuPic as stuPic4_1_0_,
        student1_.stuSex as stuSex5_1_0_ 
    from
        Address address0_ 
    left outer join
        Student student1_ 
            on address0_.addressId=student1_.addressId 
    where
        address0_.addressId=?
----------------地址信息---------------
地址信息:北京
-----------------學生信息-----------------
學生姓名:Hibernate老大

無論是從學生表查詢到地址表,還是從地址表查詢到學生表。只要有足夠的信息告訴 Hibernate 如何關聯到數據庫中對應的表,Hibernate 都會如你所愿。

3. 關聯映射中的延遲加載

關聯多表查詢時可選擇是否啟用延遲加載。

PO 之間的映射,意味著 Hibernate 不僅能查詢到指定表中數據,還能查詢相關聯表中的數據。

但,有時只需要查詢學生基本信息,并不需要地址信息,或者地址信息并不需要馬上查詢出來,能不能告訴 Hibernate,只查詢學生信息,暫且別查詢地址信息。

同樣,有時只需要查詢所在地址,并不關心地址對應學生信息。

可以啟動關聯映射中的延遲加載實現上面的需求。

學生類中修改代碼如下:

@OneToOne(targetEntity = Address.class,fetch=FetchType.LAZY)
@JoinColumn(name = "addressId")
public Address getAddress() {
    return address;
}

@OneToOne 注解有 fetch 屬性,為枚舉類型,其值可選擇:

  • FetchType.LAZY;
  • FetchType.EAGER。

其作用便是告訴 Hibernate,是否延后或立即查詢相關聯表中的數據。

執(zhí)行下面測試代碼:

try {
    transaction = session.beginTransaction();
	Student stu = (Student) session.get(Student.class, new Integer(1));
	System.out.println("----------------學生信息---------------");
	System.out.println("學生姓名:" + stu.getStuName());
	transaction.commit();
} catch (Exception e) {
	transaction.rollback();
} finally {
	session.close();
}

查看結果:

Hibernate: 
    select
        student0_.stuId as stuId1_1_0_,
        student0_.addressId as addressI6_1_0_,
        student0_.stuName as stuName2_1_0_,
        student0_.stuPassword as stuPassw3_1_0_,
        student0_.stuPic as stuPic4_1_0_,
        student0_.stuSex as stuSex5_1_0_ 
    from
        Student student0_ 
    where
        student0_.stuId=?
----------------學生信息---------------
學生姓名:Hibernate老大

Hibernate 只構建了一條簡單的 Sql 語句, 用于查詢學生信息。

繼續(xù)執(zhí)行下面測試實例:

try {
	transaction = session.beginTransaction();
    Student stu = (Student) session.get(Student.class, new Integer(1));
	System.out.println("----------------學生信息---------------");
	System.out.println("學生姓名:" + stu.getStuName());
	System.out.println("-----------------地址信息-----------------");
	System.out.println("學生家庭地址:" + stu.getAddress().getAddressName());
	transaction.commit();
} catch (Exception e) {
	transaction.rollback();
} finally {
	session.close();
}

輸出結果:

Hibernate: 
    select
        student0_.stuId as stuId1_1_0_,
        student0_.addressId as addressI6_1_0_,
        student0_.stuName as stuName2_1_0_,
        student0_.stuPassword as stuPassw3_1_0_,
        student0_.stuPic as stuPic4_1_0_,
        student0_.stuSex as stuSex5_1_0_ 
    from
        Student student0_ 
    where
        student0_.stuId=?
----------------學生信息---------------
學生姓名:Hibernate老大
-----------------地址信息-----------------
Hibernate: 
    select
        address0_.addressId as addressI1_0_0_,
        address0_.addressName as addressN2_0_0_,
        address0_.descript as descript3_0_0_ 
    from
        Address address0_ 
    where
        address0_.addressId=?
學生家庭地址:北京

Hibernate 分別構建了 2 條簡單的查詢 Sql 語句,可得出結論:

  • 只有當需要獲取地址信息時,才會構建 Sql 語句查詢地址表;

這就是關聯映射中的延遲加載。

  • @OneToOne 默認情況下是采用立即策略,通過構建多表查詢語句一次性全部查詢。

4. 小結

本節(jié)課講解了如何通過實現實體類之間的映射,以保證 Hibernate 能正常訪問開發(fā)者所需要的關聯表中的數據。其中有些細節(jié)暫未深究。

當介紹一對多、多對多映射關系時,再抽絲剝繭般展開。

OK!意猶未盡之處,下一節(jié)課程再暢聊。