日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

初识Hibernate之关联映射(一)

發布時間:2025/4/16 编程问答 20 豆豆
生活随笔 收集整理的這篇文章主要介紹了 初识Hibernate之关联映射(一) 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

?????上篇文章我們對持久化對象進行的學習,了解了它的三種不同的狀態并通過它完成對數據庫的映射操作。但這都是基于單張表的操作,如果兩張或者兩張以上的表之間存在某種關聯,我們又該如何利用持久化對象進行操作呢?本篇主要介紹的關聯映射就是針對有著某種關聯的多張表的各種操作,主要涉及內容如下:

  • 組合主鍵的映射
  • 組件的映射
  • 單向多對一的映射
  • 單向一對多的映射
  • 雙向一對多的映射
  • 級聯映射

一、組合主鍵的映射操作
?????根據我們的上篇文章,對于單一主鍵,在對象映射配置文件中使用 id標簽即可完成配置。但是,往往有些主鍵并不是單一的,它可能由多個字段組合,那么此時就不能使用 id標簽進行指定了。例如,我們有一張scores表,該表有三個字段,uid表示學生id,sub表示學生考試的學科,score表示該門考試成績。那么確定一個學生的某門考試成績就需要uid和usub,此時它們就是scores表的主鍵,因為它能唯一確定一行數據。

/*定義scores實體類*/ public class Scores {private Score scoreId; //主鍵private int score;//省略get,set方法 } public class Score implements Serializable {private int userId;private String sub;//省略get,set方法 }

在這里,我們定義scores實體類,我們將主鍵封裝成一個類score,該類必須繼承接口Serializable ,最好還能實現它的兩個方法equals和hashcode。然后就是我們的實體映射配置文件的編寫:

<class name="DbClasses.Scores" table="scores"><composite-id name="scoreId" class="DbClasses.Score"><key-property name="userId" column="userId"></key-property><key-property name="sub" column="sub"></key-property></composite-id><property name="score" column="score"></property> </class>

對于組合主鍵,我們使用標簽composite-id來配置,name和class屬性分別指定主鍵類在實體類中的名稱及其位置。該標簽下的key-property標簽則是用來指定主鍵成員對應于數據表中的具體字段的。我們運行程序,看看Hibernate為我們創建的表中是否有一個組合主鍵:

顯然,在我們的scores表中,userId和sub的組合構成了該表的主鍵。這就是組合主鍵在Hibernate中的配置情況,組合主鍵還是比較常見的。

二、組件映射
?????這里將要介紹的組件映射和上述介紹的主鍵映射名稱相似,但確實完全不同的概念,需要予以區別。假設我們有一張person表:

person表中有主鍵id,name,age字段,還有三個地址字段(往往一個人有多個地址,我們要分別進行保存)。但是這樣的一個表結構對應于我們的實體類如下:

public class Person {private int id;private String name;private int age;private String address1;private String address2;private String address3;//省略get,set方法 }

對于這樣的實體類來說,我們覺得他對于地址字段的處理是冗余的,假如某個人有十個地址,難道要在我們的實體類中配置十個屬性嗎?顯然是不合理的,Hibernate允許我們像主鍵映射一樣將所有的地址字段抽象出來一個類。

public class Person {private int id;private String name;private int age;private Address address;//省略get,set方法 } public class Address {private String address1;private String address2;private String address3;//省略get,set方法 }

重點在于我們的實體映射文件的配置,

<class name="DbClasses.Person" table="person"><id name="id" column="id"><generator class="native"></generator></id><property name="name" column="name"></property><property name="age" column="age"></property><!--映射的一個組件屬性--><component name="address" class="DbClasses.Address"><property name="address1" column="address1"></property><property name="address2" column="address2"></property><property name="address3" column="address3"></property></component> </class>

實體類中其他的屬性照常配置,對于這個Address類型的屬性,我們使用component標簽進行配置,name和class分別指定組件名和其位置,在該標簽下,使用property標簽配置組件的成員對應于數據表中的字段。然后我們刪除表,重新看看這次Hibernate為我們生成的表結構:

顯然結果是一樣的,我們使用組件映射的一個好處就在于在這個實體類中,對于數據表結構顯得非常清晰,代碼的封裝性更好,方便查錯。

三、單向多對一的映射
?????以上介紹的兩種基本映射并不屬于我們本篇將要介紹的關聯映射,關聯映射就是指在處理多張有關聯的表時,我們的實體類的配置。所謂的多對一就是指,其中一張表的主鍵是另一張表的外鍵,例如:

我們有一張Student表,一張grade表,其中grade表的主鍵id是Student表的外鍵(grade),Student中的多條記錄對應于grade的一條記錄,所以這種表的關聯又被稱作多對一的關聯關系。下面我們看看如何通過對實體類的配置達到構建這種多對一的數據表關聯。

public class Student {private int uId;private String name;private int age;private Grade grade;//省略get,set方法 } public class Grade {private int id;private String grade;//省略get,set方法 }

Student和Grade分別對應不同數據庫表的兩個實體類,但是Student實體類中有一個屬性grade指向實體類Grade。實體類映射配置文件如下:

<class name="DbClasses2.Student" table="student"><id name="uId" column="uid"><generator class="native"></generator></id><property name="name"></property><property name="age"></property><many-to-one name="grade" class="DbClasses2.Grade" column="grade_id"></many-to-one> </class><class name="DbClasses2.Grade" table="grade"><id name="id" column="id"><generator class="native"></generator></id><property name="grade" column="grade"></property> </class>

Grade實體類的配置沒什么變化,Student中使用many-to-one標簽將本實體類中屬性grade配置指向另一個實體類Grade,并用column指定外鍵名稱。也就是當Hibernate根據映射配置文件創建數據表的時候,發現屬性grade指向的是一個實體類Grade,于是把Grade表的主鍵關聯到grade字段上。我們先運行程序看看HIbernate是否為我們創建了這種外鍵關聯,然后通過插入數據進一步理解Hibernate在底層為我們做的事情。

顯然,在分別創建Student和Grade表之后,Hibernate又向數據庫發送了一條alter語句,該語句負責添加外鍵關聯。下面我們看看能否利用外鍵獲取到Grade表中的成績。

/*首先向表中插入信息*/ Student student = new Student(); student.setName("single"); student.setAge(21);Grade grade = new Grade(); grade.setGrade("優秀");student.setGrade(grade);session.save(grade); session.save(student);

我們知道,一個實體類的對象對應于數據表的一條記錄,那么grade代表Grade表的一條記錄,而該對象作為屬性值被賦值給Student中的grade屬性則表示它將自己的引用交給了Student的外鍵字段,也就是說student這條記錄可以通過外鍵字段找到grade代表的這條記錄。有點繞,但是學過數據庫原理的應該不難理解。下面我們看,如何利用外鍵獲取對應的Grade表中的一條完整記錄。

Student student = (Student)session.get(Student.class,1); Grade grade = student.getGrade(); System.out.println(grade.getId()+":"+grade.getGrade());

輸出結果:

1:優秀

顯然,我們通過Student返回的grade對象代表的就是基于Student外鍵字段值在Grade表中的一條數據。

四、單向一對多的映射
?????單向many-to-one關聯是最常見的單向關聯關系,其邏輯也趨近與我們的Sql語言,還算比較好理解。而對于單向一對多的映射則是其的一個逆向的邏輯,相對而言比較難以理解。這個多對一和一對多之間有個很明顯的區別,對于多對一的情況,我們在得到Student對象代表的一條數據記錄時,可以利用外鍵得到相對應Grade表中的一條記錄。但是反過來,如果我們想知道對于Grade表的某條記錄究竟有多少Student表記錄予以對應呢?起碼這是多對一無法直接解決的,那么我們的一對多則著重解決的就是這么一個問題。

?????所謂的一對多就是利用一的一方完成這種外鍵關聯的構建。我們先看實體類的定義:

/*student實體類的定義*/ public class Student {private int uId;private String name;private int age;//省略get,set方法 } public class Grade {private int id;private String grade;//用于給其他表映射外鍵private Set<Student> students = new HashSet<Student>(0); //省略get,set方法 }

這里我們使用set集合,其實無論是list或者map都是可以的,旨在保存多的一方的記錄。看似毫無關聯的兩張表卻可以通過配置文件完成外鍵關聯操作。有關Student實體的映射配置部分代碼和平常是一樣的,沒有變動此處不再貼出,我們主要看Grade實體類的映射配置代碼:

<class name="DbClasses2.Grade" table="grade"><id name="id" column="id"><generator class="native"></generator></id><property name="grade"/><set name="students"><key column="grade_id"></key><one-to-many class="DbClasses2.Student"></one-to-many></set> </class>

在Grade的實體類映射配置文件中,set標簽用于配置屬性students 。也就是說,當Hibernate加載到這里的時候,兩張表單獨創建完成之后,我要回到這里來,這里有一個一對多的外鍵需要更新,該外鍵的表載體在Student中,外鍵的名稱是grade_id,于是它就會去更新Student的表結構,為它添加外鍵的引用,而引用的表就是Grade。這里還看不出set的作用,我們先看Hibernate為我們創建的表關聯是否正確,然后通過存取數據來感受set的作用。

顯然,Hibernate是先單獨創建兩張表,然后發送alter語句添加外鍵引用。那究竟set有什么用呢?它里面裝的又是什么呢?
假設兩張表中有如下信息:

下面我們通過程序獲取成績為優秀的所有Student。這一點在多對一映射中是做不到的。多對一只能知道某個學生的成績是什么,但是無法直接知道成績為什么的所有學生。

Grade grade = (Grade)session.get(Grade.class,1); Set<Student> students = grade.getStudents(); //遍歷輸出所有學生姓名 Iterator<Student> iterator = students.iterator(); while(iterator.hasNext()){System.out.println(iterator.next().getName()); }

輸出結果:

從Hibernate的日志輸出中,我們可以很顯然的看出來,首先Hibernate向數據庫發送第一條select語句查詢id為1的grade記錄,然后默默的又一次發送select語句,不過這次是Student表,查詢所有grade_id為1的記錄并通過反射全部添加到set集合中。于是我們可以遍歷輸出所有Student信息。

五、雙向一對多的映射
?????雙向一對多或者雙向多對一都是一個意思,這種形式的關聯映射操作就是上述的兩種映射的結合,在多的一段配置多對一映射,在一的一段配置一對多映射。這樣,我們既可以從多的一端通過外鍵獲取到一的一端的詳細記錄又可以從一的一端通過自己的主鍵獲取到多的一端的所有對應記錄。這種方式比較簡單,此處不再贅述,我們最后看看兩個關鍵字cascade和inverse的含義和用法。

六、級聯映射
?????我們首先看級聯操作,級聯就是在兩張具有關聯關系的表操作的時候,通過操作其中一張表級聯的更新了另一張表。先看個例子:

<many-to-one name="grade" class="DbClasses2.Grade" column="grade_id" cascade="save-update" />

我們在多的一端配置cascade等于save-update,意味著我們在多的一端進行save和update的時候,數據會自動更新到Grade表中。

Student stu1 = new Student(); stu1.setName("single"); stu1.setAge(21);Grade grade = new Grade(); grade.setGrade("優秀");stu1.setGrade(grade);//session.save(grade); session.save(stu1);

上述的這段代碼完成的是一個插入操作,如果沒有設置級聯的話,該段程序必然報錯,因為grade表中無任何數據,而student代表的一條記錄的grade_id的字段卻被強行插入數值1,自然會報錯(外鍵1在grade表中找不到)。但是我們配置了級聯就不一樣了,Hibernate會先保存grade到數據庫中,然后再插入student這條記錄。從Hibernate的輸出日志中也可以看出來:

當然,除了可以在多的一端配置級聯,我們也可以在一的一端配置級聯,讓一的一端也可以級聯的操作多的一端。例如:

<set name="students" cascade="save-update"><key column="grade_id"></key><one-to-many class="DbClasses2.Student"></one-to-many> </set>

給一的一端配置級聯,然后我么通過級聯來保存多的一端的數據。

Grade grade = new Grade(); grade.setGrade("優秀");Student stu1 = new Student(); stu1.setName("single"); stu1.setAge(21);Student stu2 = new Student(); stu2.setName("cyy"); stu2.setAge(20);grade.getStudents().add(stu1); grade.getStudents().add(stu2);//session.save(stu1);sesion.save(stu2); session.save(grade);

這段代碼在沒有配置級聯的狀態下,必然會報錯。首先Hibernate根據配置文件創建了兩張表及其之間的關聯關系。執行save的時候會將grade保存到數據表中,然后Hibernate會查看自己set集合中對應的多端的記錄并根據這些記錄去更新多端表中的外鍵值,當然如果沒有保存到student表中,自然會報錯。我們看看級聯是怎么做的:

顯然,在保存好grade之后,立馬將自己set集合中的Student記錄插入到Student表中,然后通過update語句更新他們的外鍵值。而沒有設置級聯的話,第二三條Sql語句是沒有的,報錯那也是自然的。關于級聯,只要理解了它的本質,這些操作也都是可以理解的,本質上就是在做插入或者修改操作的時候如果發現自己代表的這條記錄中有外部關聯表的內容,那么則先完成對外部表的更新。這就是級聯,級聯的操作和自己關聯的外部表,當然cascade也不止這一個參數值:

cascade="all|none|save-update|delete"

其中,none表示不級聯,all表示所有操作都級聯,save-update 表示保存和修改操作進行級聯,delete表示刪除的時候級聯刪除。本質都類似,此處不再贅述。

至此,有關關聯映射的第一部分介紹完了,下篇將繼續介紹未完的其他關聯映射的操作。總結不到之處,望指出!

轉載于:https://www.cnblogs.com/yangming1996/p/7634307.html

總結

以上是生活随笔為你收集整理的初识Hibernate之关联映射(一)的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。

主站蜘蛛池模板: 国产精品女同一区二区 | 一区二区欧美在线观看 | 电车痴汉在线观看 | 免费在线看污片 | 亚洲精品中文字幕乱码三区91 | 欧美视频1区 | 亚洲第一视频在线观看 | 国产精品麻豆果冻传媒在线播放 | 男人的天堂在线 | 久久亚洲少妇 | 男女无遮挡免费视频 | 好吊操这里有精品 | 中文字幕亚洲日本 | 性色av一区二区三区免费 | 成都免费高清电影 | 国产精品久久久久久99 | caopeng在线视频| 乱色专区 | 欧美精品日韩在线观看 | 国产精品高清无码在线观看 | 亚洲女同一区二区 | 91久久精品www人人做人人爽 | 高潮毛片无遮挡免费看 | 18无套直看片红桃 | 天天爽天天射 | 日韩av成人 | 一级免费片 | 天天插视频 | 免费观看在线视频 | 免费插插视频 | 青青草手机在线 | 99国产精品一区二区三区 | 成人av专区 | 自拍一区在线 | 男男免费视频 | 夜夜综合网| 色老头在线视频 | 成人动漫视频 | 久99视频| 草碰在线| 国产宾馆实践打屁股91 | 日韩成人av片 | 91激情网| 亚洲人xxx日本人18 | 国产睡熟迷奷系列精品视频 | 我和我的太阳泰剧在线观看泰剧 | 天堂色区 | 日韩在线观看视频一区 | 亚洲欧美日韩偷拍 | 一区二区三区四区在线播放 | 男女羞羞动态图 | 日韩欧洲亚洲AV无码精品 | 操操日日 | 99黄色片| av中文网站 | 天堂资源网 | 亚洲一区二区日本 | 一区二区免费在线播放 | www.污污| 清纯唯美第一页 | 欧美日本激情 | 天天热天天干 | 羞羞涩涩视频 | 欧美 日韩 国产在线 | 黄色长视频 | 国产91精品高潮白浆喷水 | 992av| 久久精品国产清自在天天线 | 农村老女人av | 久久亚洲国产成人精品性色 | 美女流白浆视频 | av有码在线 | 精品久久久久久久久久久 | 动漫一区二区三区 | 国产精品成熟老女人 | 国产精品主播在线 | 在线香蕉| 久久久888 | 77久久| 欧美1区2区3区 | 不卡一二三 | 日韩porn | av一片 | 一本到免费视频 | 亚洲一区二区三区四区五区六区 | 老妇女性较大毛片 | 爱综合网 | 精品无码国产一区二区三区51安 | 男人和女人日批视频 | 日韩在线一二三区 | 中文字幕一区二区人妻电影丶 | 日韩中文字幕亚洲精品欧美 | 香蕉国产在线观看 | 国产精品亚洲欧美 | 国产精品性 | 国产亚洲系列 | 久久国产免费看 | 色老二导航| 精品三级电影 |