什麼是Hibernate中的關聯映射?java
簡單來講Hibernate是ORM映射的持久層框架,全稱是(Object Relational Mapping),即對象關係映射。mysql
它將數據庫中的表映射成對應的對象,以對象的形式展示,這樣咱們就能夠經過映射的對象來對數據庫中的數據進行間接的操做。sql
關聯映射是將數據庫中的表映射成與之相對應的對象,當你對這個對象進行操做的時候,Hibernate會對數據庫中對應的表執行相應的操做,你對該實體的操做實際上就是在間接的操做數據庫中與之相對應的表。數據庫
Hibernate正是實現了這種思想,達到了方便開發人員以面向對象的思想來實現對數據庫的操做。 session
Hibernate主要實現的映射關係:app
Hibernate映射的基本結構框架
hibernate在實現ORM功能的時候主要用到的文件有:映射類(*.Java)、映射文件(*.hbm.xml)和數據庫配置文件(*.properties/*.cfg.xml),它們各自的做用以下。dom
映射類(*.java):它是描述數據庫表的結構,表中的字段在類中被描述成屬性,未來就能夠實現把表中的記錄映射成爲該類的對象了。ide
映射文件(*.hbm.xml):它是指定數據庫表和映射類之間的關係,包括映射類和數據庫表的對應關係、表字段和類屬性類型的對應關係以及表字段和類屬性名稱的對應關係等。fetch
數據庫配置文件(*.properties/*.cfg.xml):它是指定與數據庫鏈接時須要的鏈接信息,好比鏈接哪一種數據庫、登陸數據庫的用戶名、登陸密碼以及鏈接字符串等。固然還能夠把映射類的地址映射信息放在這裏。
hibernate中的關聯關係有四種:一對1、一對多、多對1、多對多。
關聯關係中又分爲單向關聯與雙向關聯
單向關聯:單向關聯是指只有一方有另外一方的關聯信息而另外一方沒有關聯信息
例:
A——>B
A對象中有B對象的關聯信息
B對象中沒有A對象的關聯信息
咱們能夠經過A對象中B的關聯信息查詢或修改B對象的信息但沒法經過B對象來查詢修改A對象的信息
同理A<——B也是單向關聯
這種只是單方面的關聯咱們稱爲單向關聯
雙向關聯:雙向關聯是指兩方都有另外一方的關聯信息
例:
A<——>B
A對象中有B對象的關聯信息
B對象中也有A對象的關聯信息
咱們能夠經過A對象中B的關聯信息查詢或修改B對象的信息也能夠經過B對象來查詢修改A對象的信息
這種兩方都有另外一方的關聯信息咱們稱爲雙向關聯
單向關聯通常在一方配置多方不進行配置
如:一對多 單向關聯在「一」的一方配置文件裏進行配置,"多"的一方不進行配置
雙向關聯兩方都要配置
如:一對多 雙向關聯在「一」的一方配置文件裏須要配置,「多」的一方也須要進行配置
經過下面的代碼會慢慢了解
下面咱們來詳細瞭解一下一對1、一對多、多對1、多對多的單向和雙向關聯:
一對一關聯映射
一對一關聯:一對一是指一個對象對應一個對象 如:一我的只有一個身份證。
在兩個數據表之間的一對一關係能夠有兩種實現方法,其中一種就是經過兩個表的主鍵相關聯,另外一種是經過外鍵相關聯
如:一我的(Person)對應一個地址(Address)代碼以下。
一對一主鍵單向關聯:
Person——>Address
public class Person { private int personid; private String name; private int age; //在Person對象中有Address對象的關聯信息 private Address address; public class Address{ //Address對象中沒有Person對象的關聯信息 private int addressid; private String addressdetail;
這種單方面有另外一個對象的關聯信息的時候咱們稱爲單向關聯,再來看一下兩個表中的映射hbm.xml文件:
Person.hbm.xml
<hibernate-mapping> <class name="com.entity.Person" table="PERSON"> <id name="personid" column="presonid"> <!--基於主鍵關聯時,主鍵生成策略是foreign,代表根據關聯類生成主鍵--> <generator class="foreign"> <!--關聯持久化類的屬性名--> <param name="property">address</param> </generator> </id> <property name="name"/> <property name="age"/> <!--constrained設定爲true,表示的主鍵必須與Person中對應資料的主鍵相同。--> <one-to-one name="address" constrained="true"/> </class> </hibernate-mapping>
單向關聯和雙向關聯的區別主要在於單向只在一方配置而雙向兩方都要配置
Address.hbm.xml
由於是單方面關聯因此只在Person.hbm.xml中配置了關聯信息而Address.hbm.xml中不作任何配置
因此咱們省略Address.hbm.xml
…………
知道了一對一的單向關聯,咱們再來了解一下一對一的雙向關聯,雙向關聯結合上面的知識可能聰明的小夥伴已經想到了。下面咱們來看一下一對一的雙向關聯
一對一主鍵雙向關聯:
Person<——>Address
public class Person implements java.io.Serializable { private Long id; private String name; //雙向關聯中Person對象中有Adderss對象的關聯信息 private Address address; public class Address implements java.io.Serializable { private Long id; //Adderss對象中也有Person對象的關聯信息 private Person person; private String detail;
這種兩方面都有另外一個對象的關聯信息的時候咱們稱爲雙向關聯,再來看一下兩個表中的映射hbm.xml文件:
Person.hbm.xml
<hibernate-mapping> <class name="entity.Person" table="person"> <id name="id" type="java.lang.Long"> <column name="id" /> <generator class="identity" /> </id> <property name="name" type="java.lang.String"> <column name="name" length="24" not-null="true"> <comment>姓名</comment> </column> </property> <one-to-one name="address"/> </class> </hibernate-mapping>
單向關聯和雙向關聯的區別主要在於單向只在一方配置而雙向兩方都要配置
Address.hbm.xml
<hibernate-mapping> <class name="entity.Address" table="address" catalog="mydb"> <id name="id" type="java.lang.Long"> <column name="id" /> <!-- class="foreign": 一對一主鍵映射中,使用另一個相關聯的對象的標識符 --> <generator class="foreign"> <param name="property">person</param> </generator> </id> <property name="detail" type="java.lang.String"> <column name="detail" length="120" not-null="true"> <comment>詳細地址</comment> </column> </property> <!-- 表示在address表存在一個外鍵約束,外鍵參考相關聯的表person --> <one-to-one name="person" constrained="true" /> </class> </hibernate-mapping>
當咱們操做Person對象時,能夠對Address對象進行操做,也能夠操做Address對象時對Person對象進行操做這樣就造成了雙向的關聯
雙向關聯還須要在hibernate.cfg.xml中進行配置
<hibernate-configuration> <session-factory> <property name="connection.username">root</property> <property name="connection.url"> jdbc:mysql://localhost:3306/testdb </property> <property name="dialect"> org.hibernate.dialect.MySQLDialect </property> <property name="connection.password">xiaohui</property> <property name="connection.driver_class"> com.mysql.jdbc.Driver </property> <property name="show_sql">true</property> <property name="format_sql">true</property>
<!--在hibernate.cfg.xml中配置hbm.xml文件--> <mapping resource="com/entity/Person.hbm.xml" /> <mapping resource="com/entity/Address.hbm.xml" /> </session-factory> </hibernate-configuration>
咱們再來看一下一對一的外鍵關聯
一對一外鍵單向關聯:
Person——>Address
public class Person { private int personid; private String name; private int age; private Address address; public class Address{ private int addressid; private String addressdetail;
雙向和單向關聯你們應該已經瞭解了 這裏就很少作介紹了直接上代碼:
Address.hbm.xml
<!--address中不作任何配置因此咱們省略-->
…………………………
<!--單向關聯和雙向關聯的區別在於單向關聯只在一方配置雙向關聯兩方都要配置--> Person.hbm.xml <hibernate-mapping> <class name="com.entity.Person" table="PERSON"> <id name="personid"> <generator class="identity"/> </id> <property name="name"/> <property name="age"/> <!--用來映射關聯PO column是Address在該表中的外鍵列名,增長unique變成惟一的--> <many-to-one name="address" unique="true"/> </class> </hibernate-mapping>
外鍵關聯和主鍵關聯不一樣的地方是採用<many-to-one>標籤來映射,一對一惟一外鍵關聯映射實際上是多對一的特例。<many-to-one>指定多的一端unique爲true,這樣就限制了多的一端的多重性爲一,就是這樣來映射的。
一對一外鍵雙向關聯:
Person<——>Address
public class Person implements java.io.Serializable { private Long id; private String name; private Address address; public class Address implements java.io.Serializable { private Long id; private Person person; private String detail;
Person.hbm.xml <hibernate-mapping> <class name="com.entity.Person" table="person"> <id name="personid" type="java.lang.Long"> <column name="personid" /> <generator class="identity" /> </id> <property name="name" type="java.lang.String"> <column name="name" length="24" not-null="true"> <comment>姓名</comment> </column> </property>
<!--雙向關聯配置--> <one-to-one name="address" /> </class> </hibernate-mapping> Address.hbm.xml <hibernate-mapping> <class name="com.entity.Address" table="address" catalog="testdb"> <id name="addressid" type="java.lang.Long"> <column name="addressid" /> <generator class="identity" /> </id> <property name="detail" type="java.lang.String"> <column name="detail" length="120" not-null="true"> <comment>詳細地址</comment> </column> </property> <many-to-one name="person" class="entity.Person" unique="true"> <column name="personid"> <comment>人的ID</comment> </column> </many-to-one> </class> </hibernate-mapping>
單向關聯和雙向關聯的區別主要在於單向只在一方配置而雙向兩方都要配置因此一對一雙向關聯比單向關聯多了一個在Person.hbm.xml文件中配置<one-to-one name="address" />
雙向關聯還須要在hibernate.cfg.xml中進行配置
<hibernate-configuration> <session-factory> <property name="connection.username">root</property> <property name="connection.url"> jdbc:mysql://localhost:3306/testdb </property> <property name="dialect"> org.hibernate.dialect.MySQLDialect </property> <property name="connection.password">xiaohui</property> <property name="connection.driver_class"> com.mysql.jdbc.Driver </property> <property name="show_sql">true</property> <property name="format_sql">true</property> <!--在hibernate.cfg.xml中配置hbm.xml文件--> <mapping resource="com/entity/Person.hbm.xml" /> <mapping resource="com/entity/Address.hbm.xml" /> </session-factory> </hibernate-configuration>
注意:由於一對一的主鍵關聯映射擴展性很差,當咱們的須要發生改變想要將其變爲一對多的時候變沒法操做了,因此咱們遇到一對一關聯的時候常常會採用惟一外鍵關聯來解決問題,而不多使用一對一主鍵關聯。
一對多關聯映射
一對多關聯:一對可能是指一個對象對應多個對象 一樣也分爲單向關聯和雙向關聯 如:一個教室能夠有多個學生
一對多單向關聯:
Classes——>Student
public class Classes { private int id; private String name; //Set支持延遲加載由於多個學生因此咱們用Set集合關聯 private Set students; }
public class Student { private int id; private String name; }
單向關聯只需在一方配置hbm.xml文件Student不須要配置因此就省略了
Classes對象中使用了set屬性,可是隻是說明了延遲加載的屬性,並無爲屬性配置對應的對象,屬性的對象是要在映射文件中來配置的,須要添加set標籤,並在set標籤中添加<one-to-many>標籤,具體以下代碼:
Classes.hbm.xml
<hibernate-mapping> <class name="com.hibernate.Classes" table="t_classes"> <id name="id"> <generator class="native"/> </id> <property name="name"/> <set name="students"> <key column="classesid"></key> <one-to-many class="com.hibernate.Student"></one-to-many> </set> </class> </hibernate-mapping>
由於Classes一方是一方對應的Student是多方 因此咱們要用<set>來關聯一方
Student.hbm.xml不作任何改變
省略………………
一對多雙向關聯:
Classes<——>Student
public class Classes { private int id; private String name; //Set支持延遲加載 private Set<Student> students; } public class Student { private int id; private String name; //添加class對象關聯信息由於是一方因此咱們用一個對象關聯 private Classes classes; }
Classes.hbm.xml
由於與單向一對多配置同樣因此就省略了 能夠參考上面單向一對多的代碼
Student.hbm.xml
雙向咱們須要兩方都要配置代碼以下:
<hibernate-mapping> <class name="com.hibernate.Student" table="t_student"> <id name="id"> <generator class="native"/> </id> <property name="name"/> <!-- 在多的一端Student中添加一行新的Classes列 ,而且列的名稱要和Classes.hbm.xml的列明相同--> <many-to-one name="classes" column="classesid"></many-to-one> </class> </hibernate-mapping>
由於Student一方是多方對應的Classes是一方 因此咱們要用<many-to-one>來關聯一方
多對多關聯映射
多對多關聯:多對多關聯是指多個對象對應多個對象 如:老師能夠有多個學生,學生也能夠有多個老師
多對多單向關聯:
Teacher——>Student
public class Teacher { private int id; private String name; private Set<Student> students = new HashSet<Student>(); } public class Student { private int id; private String name; private String title; }
Teacher.hbm.xml
<hibernate-mapping> <class name="com.hibernate.Teacher" table="t_teacher"> <id name="id"> <generator class="native"/> </id> <property name="name"/>
<!--生成一張新表存放兩個關聯對象的ID--> <set name="students" table="Teacher_Sutdent">
<!--將Teacher表的外鍵關聯 注意不是對象的屬性是表中的字段--> <key column="teacher_id"></key>
<!--將Student表的外鍵關聯 注意不是對象的屬性是表中的字段-->
<many-to-many class="com.hibernate.Student" column="student_id"></many-to-many>
</set>
</class>
</hibernate-mapping>
文件中要使用<many-to-many>標籤,而且在標籤中添加上對應的列關係,由於你要讓兩個對象中都要清楚它們之間的映射是如何使用的,而且在生成的關係表中哪一列是對應的本身的外鍵,因此要在該標籤中指明,另外在<set>標籤中添加table屬性會指明要生成新表,下面的示例中添加了t_user_role,因此會生成新的關聯表。
Student.hbm.xml不作任何配置因此省略
…………
多對多雙向關聯:
Teacher<——>Student
public class Teacher { private int id; private String name; private Set<Student> students = new HashSet<Student>(); } public class Student { private int id; private String name; private String title; private Set<Teacher> teachers = new HashSet<Teacher>(); }
Teacher.hbm.xml同單向多對多同樣故省略
…………
Student.hbm.xml
<hibernate-mapping> <class name="com.hibernate.Student" table="t_student"> <id name="id"> <generator class="native"/> </id> <property name="name"/> <!--生成一張新表存放兩個表的Id--> <set name="teachers" table="Teacher_Student"> <!--將Teacher表的外鍵關聯 注意不是對象的屬性是表中的字段--> <key column="student_id"></key> <!--將Student表的外鍵關聯 注意不是對象的屬性是表中的字段--> <many-to-many class="com.hibernate.Teacher" column="teacher_id"></many-to-many> </set> </class> </hibernate-mapping>
多對一關聯
對比一對一關聯映射和多對一惟一外鍵關聯映射,其實它們兩個都是使用了<many-to-one>本質上都是外鍵約束,只不過一對一的是惟一映射,須要添加unique="true"的屬性,其它的它們兩個是相同的。
多對一關聯:多對一關聯是指多個對象對應一個對象 如:多個員工對應一個部門
多對一單向關聯:
public class Department { private int id; private String name; } public class Employee { private int id; private String name; private Department depart;//注意這裏是以部門的對象來做爲員工的屬性的,這個思想很關鍵,是創建起部門和員工關聯的關鍵 }
Department.hbm.xml不作任何配置故省略
…………
Employee.hbm.xml
<hibernate-mapping package="com.suo.domain"> <class name="Employee"> <id name="id"> <generator class="native"/> </id> <property name="name"/> <many-to-one name="depart"></many-to-one> <!-- many-to-one指明瞭外鍵 ,會根據反射機制,找到要和Employee創建多對一關係的類,該列默認的是能夠爲空的--> </class> </hibernate-mapping>
多對一雙向關聯:
public class Department { private int id; private String name; private Set<Employee> emps;//用集合來存儲員工 } public class Employee { private int id; private String name; private Department depart;//注意這裏是以部門的對象來做爲員工的屬性的,這個思想很關鍵,是創建起部門和員工關聯的關鍵 }
Departement .hbm.xml
<hibernate-mapping package="com.suo.domain"> <class name="Department"> <id name="id"> <generator class="native"/> </id> <property name="name"/> <set name="emps"> <key column="depart_id"/><!-- key指明瞭員工表中的外鍵--> <one-to-many class="Employee"/><!-- one-to-many指明瞭和哪一個類進行一對多的映射 --> </set> <!-- 用set標籤表示Department中的員工集合的屬性,這個屬性並無映射到數據庫中的部門表中, 即部門表中,並無emps這樣的一個列。 --> </class> </hibernate-mapping>
Employee.hbm.xml同單向關聯配置相同故省略
…………
級聯操做 Cascade:
一.簡單的介紹
cascade和inverse (Employee – Department)
l Casade用來講明當對主對象進行某種操做時是否對其關聯的從對象也做相似的操做,經常使用的cascade:
none,all,save-update,delete, lock,refresh,evict,replicate,persist,
merge,delete-orphan(one-to-many)。
通常對many-to-one,many-to-many不設置級聯,
在<one-to-one>和<one-to-many>中設置級聯。
l inverse表「是否放棄維護關聯關係」(在Java裏兩個對象產生關聯時,對數據庫表的影響),在one-to-many和many-to-many的集合定義中使用,inverse=」true」表示該對象不維護關聯關係;
該屬性的值通常在使用有序集合時設置成false(注意hibernate的缺省值是false)。
one-to-many維護關聯關係就是更新外鍵。many-to-many維護關聯關係就是在中間表增減記錄。
注: 配置成one-to-one的對象不維護關聯關係
二,屬性的解析
class元素的lazy屬性設定爲true,表示延遲加載,若是lazy設爲false,則表示當即加載。如下對這二點進行說明。
當即加載:表示Hibernate在從數據庫中取得數據組裝好一個對象(如學生1)後, 會當即再從數據庫取得數據組裝此對象所關聯的對象(如學生證1)。
延遲加載:表示Hibernate在從數據庫中取得數據組裝好一個對象(如學生1)後,不會當即再從數據庫中取得數據組裝此對象所關聯的對象(如學生1),而是等到須要時,纔會從數據庫取得數據組裝此關聯對象。
<one-to-one>元素的cascade屬性代表操做是否從父對象級聯到被關聯的對象,
它的取得能夠是如下幾種:
none:在保存,刪除或修改當前對象時,不對其附屬對象(關聯對象)進行級聯操做。它是默認值。
save-update:在保存,更新當前對象時,級聯保存,更新附屬對象(臨時對象,遊離對象)。
delete:在刪除當前對象時,級聯刪除附屬對象。
all:全部狀況下均進行級聯操做,即包含save-update和delete操做。
delete-orphan:刪除和當前對象解除關係的附屬對象。
<one-to-one>元素的fetch屬性的可選值是join和select,默認是select。當fetch屬性設定爲join時,表示鏈接抓取(Join fetching):Hibernate經過在Select語句中使用outer join(外鏈接)來得到對象的關聯實例或者關聯集合。
當fetch屬性設定爲select時,表示查詢抓取(Select fetching):須要另外發送一條Select語句抓取當前對象的關聯實體或集合。
三。代碼練習
<set name="emps" cascade="save-update">
<key column="depart_id"/>
<one-to-many class="Employee"/>
</set>
<set name="students" table="taacher_student" inverse="true"><!-- table是用來指定中間表的屬性 -->
<key column="teacher_id"></key><!-- 查找教師id時,連接中間表表的teacher_id -->
<many-to-many class="Student" column="student_id"></many-to-many>
</set>
關係映射總結:
單向關聯
一對一主鍵關聯:單向關聯時咱們須要在有關聯信息一方的配置文件里加入<one-to-one constrained="true">而且將constrained屬性設置爲true 表示的主鍵必須與這個對象中對應資料的主鍵相同
一對一外鍵關聯:單向關聯時咱們須要在有關聯信息一方的配置文件里加入<many-to-one unique="true">而且將unique屬性設置爲true 表示這個主鍵是惟一的
一對多單向關聯:單向關聯時咱們須要在有關聯信息一方的配置文件里加入<set>在<set>中加入<one-to-many/>
<set>
<key column="關聯的外鍵">
<one-to-many/>
</set>
多對多單向關聯:單向關聯時咱們須要在有關聯信息一方的配置文件里加入<set>在<set 中生成一張新表用來存放兩個表的外鍵table="">中加入<key column="當前表的外鍵ID"><many-to-many clasee="關聯對象路徑" column="關聯對象表的Id">
<set table="">
<key column=""/>
<many-to-many class="" column="">
</set>
多對一單向關聯:單向關聯時咱們須要在有關聯信息一方的配置文件里加入<many-to-one>
雙向關聯
一對一主鍵關聯:在從表的一方加入<one-to-one constrained="true">還須要在主表加入<one-to-one>
一對一外鍵關聯:除了在從表中加入<many-to-one unique="true">也須要在主表加入<one-to-one>
一對多雙向關聯:除了在一方中加入<set><one-to-many></set>還須要在多放加入<many-to-one>
多對多雙向關聯:須要在兩方都加入<set><many-to-many></set> 注:<set>中的table="表名" 代表兩方的配置要同樣
<set name="關聯對象的屬性名" table="生成一張新表">
<key column="當前對象數據庫表的外鍵"/>
<many-to-many class="關聯對象的類路徑" column="關聯對象數據庫表的外鍵">
</set>
多對一雙向關聯:要在多方中加入<many-to-one>還要在一方中加入<set>
<set>
<key column="關聯外鍵"/>
<one-to-many>
</set>