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

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

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

1. 前言

本節(jié)課,咱們一起繼續(xù)聊聊多對(duì)多關(guān)聯(lián)映射。通過(guò)本節(jié)課程,你將了解到:

  • 多對(duì)多關(guān)聯(lián)映射的實(shí)現(xiàn);
  • 雙向多對(duì)多關(guān)聯(lián)映射的實(shí)現(xiàn)。

2. 多對(duì)多關(guān)聯(lián)映射

首先了解表中的多對(duì)多關(guān)系,學(xué)生表中的數(shù)據(jù)和課程表中的數(shù)據(jù)就存在多對(duì)多關(guān)系。

一名學(xué)生可以選修多門(mén)課程,一門(mén)課程可以供多名學(xué)生選修。

數(shù)據(jù)庫(kù)通過(guò)主外鍵的機(jī)制描述表中的數(shù)據(jù)之間的關(guān)系。對(duì)于存在多對(duì)多關(guān)系的數(shù)據(jù)表,借助于中間表,分拆成兩個(gè)一對(duì)多(或者多對(duì)一)。

圖片描述

中間表的出現(xiàn),完美地表述了學(xué)生數(shù)據(jù)和課程數(shù)據(jù)之間的多對(duì)多關(guān)系。

數(shù)據(jù)庫(kù)的世界中有學(xué)生表、課程表,自然,Java 程序中就會(huì)有學(xué)生實(shí)體類(lèi)、課程實(shí)體類(lèi)。

不對(duì),好像遺漏了什么!

別忘了,表是有 3 張的(不是還有中間表嗎)。那么 Java 程序中的實(shí)體類(lèi)是不是應(yīng)該也要有 3 個(gè):

  • 學(xué)生表對(duì)應(yīng)的實(shí)體類(lèi);
  • 班級(jí)表對(duì)應(yīng)的實(shí)體類(lèi);
  • 中間表對(duì)應(yīng)的實(shí)體類(lèi)。

至于中間表所對(duì)應(yīng)的實(shí)體類(lèi)是否應(yīng)該有:答案是可以有、也可以沒(méi)有。

如果中間表僅僅只是記載了學(xué)生和課程的關(guān)系,中間表的角色定位只是一個(gè)橋梁。這種情況下,Java 程序中可以不描述中間表結(jié)構(gòu)。

Java 程序中的實(shí)體類(lèi)不僅僅是用來(lái)模仿表結(jié)構(gòu),更多是看上了表中的數(shù)據(jù)。

如果中間表除了連接作用,還保存了程序中需要的數(shù)據(jù),則 Java 程序需要一個(gè)實(shí)體類(lèi)填充數(shù)據(jù)。如:

圖片描述

針對(duì)這 2 種情況,實(shí)體類(lèi)之間的映射關(guān)系會(huì)有微妙的變化。

3. 沒(méi)有中間表實(shí)體類(lèi)的映射

如果中間表僅僅只是充當(dāng)橋梁作用,沒(méi)有程序需要的實(shí)質(zhì)性數(shù)據(jù)時(shí),程序中可以沒(méi)有中間表對(duì)應(yīng)的實(shí)體類(lèi)。

學(xué)生和課程的關(guān)系,直接在學(xué)生類(lèi)和課程類(lèi)中體現(xiàn)彼此關(guān)系就可以:

新建課程實(shí)體類(lèi):

@Entity
public class Course {
	private Integer courseId;
	private String courseName;
	private String courseDesc;

	@Id
	@GeneratedValue(strategy = GenerationType.IDENTITY)
	public Integer getCourseId() {
		return courseId;
	}
  //省略其它代碼
}

因?yàn)橐幻麑W(xué)生對(duì)應(yīng)多門(mén)課程,在學(xué)生實(shí)體類(lèi)中添加集合屬性:

private Set<Course> courses;

完成程序級(jí)別上的關(guān)系描述后,還需告訴 Hibernate,實(shí)體類(lèi)中的集合屬性數(shù)據(jù)來(lái)自哪一張以及如何獲?。?/p>

為了把問(wèn)題簡(jiǎn)單化,在學(xué)生實(shí)體類(lèi)中只體現(xiàn)和課程的關(guān)系 ,前面映射內(nèi)容注釋或刪除。

學(xué)生實(shí)體類(lèi)的完整描述:

private Set<Course> courses;
@ManyToMany(targetEntity = Course.class)
@JoinTable(name = "score", joinColumns = @JoinColumn(name = "stuId", referencedColumnName = "stuId"), 
inverseJoinColumns = @JoinColumn(name = "courseId", referencedColumnName = "courseId"))
public Set<Course> getCourses() {
	return courses;
}
  • @ManyToMany 告訴 Hibernate, course 集合中的數(shù)據(jù)來(lái)自課程表 ;
  • @JoinTable 告訴 Hibernate 獲取課程表中數(shù)據(jù)時(shí)需要借助 score 中間表。分別描述中間表和學(xué)生表、課程表的連接字段。

在 Hibernate 主配置文件中修改或添加如下信息:

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

執(zhí)行下面的測(cè)試實(shí)例:

@Test
public void testGetStuAndCourse() {
	HibernateTemplate<Student> hibernateTemplate = new HibernateTemplate<Student>();
}

查看 MySql 中的表:

圖片描述

切記把下面的信息修改回來(lái):

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

手工添加測(cè)試數(shù)據(jù):

圖片描述

好!通過(guò)測(cè)試實(shí)例見(jiàn)證 Hibernate 的神奇。

HibernateTemplate<Student> hibernateTemplate = new HibernateTemplate<Student>();
hibernateTemplate.template(new Notify<Student>() {
	@Override
	public Student action(Session session) {
		Student stu=(Student)session.get(Student.class, new Integer(1));
		System.out.println("---------------------------");
		System.out.println("學(xué)生姓名:"+stu.getStuName());
		System.out.println("----------------------------");
		System.out.println("學(xué)生選修課程數(shù):"+stu.getCourses().size());
		return stu;
}
});

查看控制臺(tái)上面的輸出結(jié)果:

Hibernate: 
    select
        student0_.stuId as stuId1_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é)生姓名:Hibernate
----------------------------
Hibernate: 
    select
        courses0_.stuId as stuId1_1_1_,
        courses0_.courseId as courseId2_2_1_,
        course1_.courseId as courseId1_0_0_,
        course1_.courseDesc as courseDe2_0_0_,
        course1_.courseName as courseNa3_0_0_ 
    from
        score courses0_ 
    inner join
        Course course1_ 
            on courses0_.courseId=course1_.courseId 
    where
        courses0_.stuId=?
學(xué)生選修課程數(shù):2

Hibernate 構(gòu)建了兩條 SQL 語(yǔ)句,先是查詢到學(xué)生信息,需要課程信息時(shí),再通過(guò)中間表連接到課程表,查詢出課程相關(guān)信息。

可得出結(jié)論:默認(rèn)情況下,Hibernate 使用了延遲加載。如此做,Hibernate 是考慮了性能的。

4. 考慮中間表的映射

命名為 score 的中間表除了維系學(xué)生表和課程表的關(guān)系,還存儲(chǔ)有學(xué)生成績(jī)。如果程序中需要成績(jī)數(shù)據(jù),則需要?jiǎng)?chuàng)建一個(gè)成績(jī)實(shí)體類(lèi)。

現(xiàn)在就有了學(xué)生、課程、成績(jī) 3 個(gè) 實(shí)體類(lèi)。本質(zhì)是映射成兩個(gè)多對(duì)一(或一對(duì)多)的關(guān)系:

  • 學(xué)生實(shí)體類(lèi)和成績(jī)實(shí)體類(lèi)一對(duì)多;
  • 課程實(shí)體類(lèi)和成績(jī)實(shí)體類(lèi)的一對(duì)多:

具體的代碼就不再貼出,大家可參考一對(duì)多的課程內(nèi)容。

本節(jié)課不關(guān)心學(xué)生的課程成績(jī)是多少,只關(guān)心,如何通過(guò)學(xué)生找到課程,或通過(guò)課程找到學(xué)生。

有一個(gè)地方需要注意:

默認(rèn)情況下,中間表使用課程 ID 和學(xué)生 ID 聯(lián)合做主鍵,也可以提供一個(gè)自定義的主鍵。

5. 雙向多對(duì)多映射

前面實(shí)現(xiàn)了學(xué)生查詢到課程,如何在查詢課程時(shí),查詢到學(xué)生信息。很簡(jiǎn)單,在課程 PO 中,添加學(xué)生集合屬性:

 // 學(xué)生信息
 private Set<Student> students;

同樣使用 @ManyToMany 注解告訴 Hibernate 數(shù)據(jù)源頭及查詢方法:

private Set<Student> students;
@ManyToMany(targetEntity = Student.class, mappedBy = "courses")
public Set<Student> getStudents() {
	return students;
}

執(zhí)行下面的測(cè)試實(shí)例:

HibernateTemplate<Course> hibernateTemplate = new HibernateTemplate<Course>();
hibernateTemplate.template(new Notify<Course>() {
	@Override
	public Course action(Session session) {
		Course course=(Course)session.get(Course.class, new Integer(1));
		System.out.println("---------------------------");
		System.out.println("課程名稱:"+course.getCourseName());
		System.out.println("----------------------------");
		System.out.println("選修此課程的學(xué)生數(shù):"+course.getStudents().size());
		return course;
	}
});

控制臺(tái)輸出結(jié)果:

Hibernate: 
    select
        course0_.courseId as courseId1_0_0_,
        course0_.courseDesc as courseDe2_0_0_,
        course0_.courseName as courseNa3_0_0_ 
    from
        Course course0_ 
    where
        course0_.courseId=?
---------------------------
課程名稱:java
----------------------------
Hibernate: 
    select
        students0_.courseId as courseId2_0_1_,
        students0_.stuId as stuId1_2_1_,
        student1_.stuId as stuId1_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
        score students0_ 
    inner join
        Student student1_ 
            on students0_.stuId=student1_.stuId 
    where
        students0_.courseId=?
選修此課程的學(xué)生數(shù):2

同樣,Hibernate 采用的是延遲加載模式。先查詢課程信息,當(dāng)開(kāi)發(fā)者需要學(xué)生信息時(shí),才構(gòu)建一條利用中間表進(jìn)入學(xué)生表的 SQL 查詢到學(xué)生信息。

可通過(guò)學(xué)生表查詢到課程表 ,也能從課程表查詢到學(xué)生表,這種多對(duì)多關(guān)聯(lián)映射稱為雙向映射關(guān)聯(lián)。

6. 小結(jié)

本節(jié)課和大家一起聊了聊多對(duì)多映射的實(shí)現(xiàn)。多對(duì)多是一種常見(jiàn)的關(guān)系。

多對(duì)多的映射實(shí)現(xiàn)可以有 2 種方案。使用中間表映射,或不使用中間表映射。

下一節(jié)課,繼續(xù)講解多對(duì)多映射中的添加、更新級(jí)聯(lián)操作,相信會(huì)給你帶來(lái)更多的驚喜。