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

首頁(yè) 慕課教程 Hibernate 入門教程 Hibernate 入門教程 Hibernate 一對(duì)一關(guān)聯(lián)映射

Hibernate 一對(duì)一關(guān)聯(lián)映射

1. 前言

本節(jié)課程和大家一起聊聊關(guān)聯(lián)映射。通過(guò)本節(jié)課程的學(xué)習(xí),你將了解到:

  • 什么是關(guān)聯(lián)映射;
  • 如何實(shí)現(xiàn)一對(duì)一關(guān)聯(lián)映射。

2. 關(guān)聯(lián)映射

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

表與表之間的數(shù)據(jù)根據(jù)彼此的關(guān)系可分為:

  • 一對(duì)一關(guān)系: 如老公表和老婆表的關(guān)系;
  • 一對(duì)多關(guān)系: 如用戶表和銀行賬號(hào)表關(guān)系;
  • 多對(duì)一關(guān)系: 如銀行帳號(hào)表對(duì)用戶表關(guān)系;
  • 多對(duì)多關(guān)系: 如學(xué)生表和課程表關(guān)系。

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

以上都是關(guān)系型數(shù)據(jù)庫(kù)中的基礎(chǔ)知識(shí),美好的回憶有助于鞏固。

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

  • 在程序中構(gòu)建一個(gè)與表結(jié)構(gòu)相似的類(這個(gè)類可稱為實(shí)體 [entity] 類);
  • 使用注解或 XML 語(yǔ)法把類結(jié)構(gòu)表結(jié)構(gòu)關(guān)聯(lián)映射起來(lái)(此時(shí)這個(gè)類可稱為 PO)。

有了 PO,Hibernate 就能在程序和數(shù)據(jù)庫(kù)之間進(jìn)行數(shù)據(jù)貿(mào)易往來(lái)。

2.1 新的需求總是接踵而至

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

程序說(shuō):親愛(ài)的 Hibernate,幫我查詢一下學(xué)生信息和學(xué)生的家庭地址信息。

差點(diǎn)忘記告訴你:學(xué)生信息學(xué)生的家庭地址信息分別存放在兩張表中,且一名學(xué)生只能有一個(gè)地址。

這是假設(shè),所以請(qǐng)不要糾結(jié)這種假設(shè)。

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

  1. 首先須確定數(shù)據(jù)庫(kù)中存在學(xué)生表和地址表,并確定兩者關(guān)系。使用地址編號(hào) addressId 字段作共同字段,addressId 在地址表中是主鍵,在學(xué)生表中是外鍵。

圖片描述

  1. 回到程序,構(gòu)建兩個(gè)類:Student 類、Address 類,添加注解描述。分別映射學(xué)生表、地址表。
    Hibernate 說(shuō):還不夠。

數(shù)據(jù)庫(kù)中的表之間是有關(guān)系的,這種關(guān)系在 Student 類Address 類 中也必須體現(xiàn)出來(lái)。
這也是 Hibernate 能查詢到多表中數(shù)據(jù)的核心要求。

2.2 PO 之間映射表之間的關(guān)系

從編碼層面上講,就是如何在 Student 類Address 類 之間體現(xiàn)出數(shù)據(jù)庫(kù)表中數(shù)據(jù)之間的關(guān)系。

先從 Student 類 中開(kāi)始,在 Student 類 中添加一個(gè)屬性字段。

private Address address;

address 屬性是一個(gè) Address 類類型,數(shù)據(jù)庫(kù)不認(rèn)得這玩意兒,Hibernate 表示開(kāi)始要一個(gè)頭兩個(gè)大了,眩暈啦。

null 你先進(jìn)入學(xué)生表,然后根據(jù)學(xué)生表中的 addressId 進(jìn)入到地址表,找到對(duì)應(yīng)數(shù)據(jù)。

Hibernate 又沒(méi)有讀心術(shù),它如何知道你心里所想。

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

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

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

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

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

Hibernate 創(chuàng)建完畢后,添加幾條測(cè)試數(shù)據(jù),操作完成后別忘記改回來(lái)。

此處操作自動(dòng)完成!相信聰明如你,一定沒(méi)問(wèn)題。

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

圖片描述

2.3 測(cè)試時(shí)間

查詢學(xué)生及學(xué)生的地址信息:

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

輸出結(jié)果:

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=?
----------------學(xué)生信息---------------
學(xué)生姓名:Hibernate老大
-----------------地址信息-----------------
學(xué)生家庭地址:北京

Hibernate 使用 left outer join 構(gòu) 建一條 Sql 語(yǔ)句,一次性訪問(wèn) 2 張表,同時(shí)獲取了學(xué)生信息和地址信息;

請(qǐng)問(wèn) Hibernate,你能不能查詢地址信息時(shí),查詢出地址是哪個(gè)學(xué)生的

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

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

  • Student 類已經(jīng)使用了 @OneToOne 映射。mappedBy=“address” 意思是說(shuō):Hibernatestudent 類中已經(jīng)說(shuō)明的夠清楚了吧,這里就不要我再啰嗦了。

測(cè)試實(shí)例:

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("-----------------學(xué)生信息-----------------");
	System.out.println("學(xué)生姓名:" + address.getStudent().getStuName());
	transaction.commit();
} catch (Exception e) {
	transaction.rollback();
} finally {
	session.close();
}

輸出結(jié)果:Hibernate 自動(dòng)構(gòu)建了多表查詢語(yǔ)句,一次性從數(shù)據(jù)庫(kù)獲取所有數(shù)據(jù)。

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=?
----------------地址信息---------------
地址信息:北京
-----------------學(xué)生信息-----------------
學(xué)生姓名:Hibernate老大

無(wú)論是從學(xué)生表查詢到地址表,還是從地址表查詢到學(xué)生表。只要有足夠的信息告訴 Hibernate 如何關(guān)聯(lián)到數(shù)據(jù)庫(kù)中對(duì)應(yīng)的表,Hibernate 都會(huì)如你所愿。

3. 關(guān)聯(lián)映射中的延遲加載

關(guān)聯(lián)多表查詢時(shí)可選擇是否啟用延遲加載。

PO 之間的映射,意味著 Hibernate 不僅能查詢到指定表中數(shù)據(jù),還能查詢相關(guān)聯(lián)表中的數(shù)據(jù)。

但,有時(shí)只需要查詢學(xué)生基本信息,并不需要地址信息,或者地址信息并不需要馬上查詢出來(lái),能不能告訴 Hibernate,只查詢學(xué)生信息,暫且別查詢地址信息。

同樣,有時(shí)只需要查詢所在地址,并不關(guān)心地址對(duì)應(yīng)學(xué)生信息。

可以啟動(dòng)關(guān)聯(lián)映射中的延遲加載實(shí)現(xiàn)上面的需求。

學(xué)生類中修改代碼如下:

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

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

  • FetchType.LAZY
  • FetchType.EAGER。

其作用便是告訴 Hibernate,是否延后或立即查詢相關(guān)聯(lián)表中的數(shù)據(jù)。

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

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

查看結(jié)果:

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=?
----------------學(xué)生信息---------------
學(xué)生姓名:Hibernate老大

Hibernate 只構(gòu)建了一條簡(jiǎn)單的 Sql 語(yǔ)句, 用于查詢學(xué)生信息。

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

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

輸出結(jié)果:

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=?
----------------學(xué)生信息---------------
學(xué)生姓名: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=?
學(xué)生家庭地址:北京

Hibernate 分別構(gòu)建了 2 條簡(jiǎn)單的查詢 Sql 語(yǔ)句,可得出結(jié)論:

  • 只有當(dāng)需要獲取地址信息時(shí),才會(huì)構(gòu)建 Sql 語(yǔ)句查詢地址表;

這就是關(guān)聯(lián)映射中的延遲加載。

  • @OneToOne 默認(rèn)情況下是采用立即策略,通過(guò)構(gòu)建多表查詢語(yǔ)句一次性全部查詢。

4. 小結(jié)

本節(jié)課講解了如何通過(guò)實(shí)現(xiàn)實(shí)體類之間的映射,以保證 Hibernate 能正常訪問(wèn)開(kāi)發(fā)者所需要的關(guān)聯(lián)表中的數(shù)據(jù)。其中有些細(xì)節(jié)暫未深究。

當(dāng)介紹一對(duì)多、多對(duì)多映射關(guān)系時(shí),再抽絲剝繭般展開(kāi)。

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