首先我們了解一個名詞ORM匙赞,全稱是(Object Relational Mapping)冶匹,即對象關(guān)系映射撒蟀。ORM的實現(xiàn)思想就是將關(guān)系型數(shù)據(jù)庫中表的數(shù)據(jù)映射成對象椰弊,以對象的形式展現(xiàn),這樣開發(fā)人員就可以把對數(shù)據(jù)庫的操作轉(zhuǎn)化為對這些對象的操作瓤鼻。Hibernate正是實現(xiàn)了這種思想秉版,達到了方便開發(fā)人員以面向?qū)ο蟮乃枷雭韺崿F(xiàn)對數(shù)據(jù)庫的操作。
Hibernate在實現(xiàn)ORM功能的時候主要用到的文件有:映射類(*.java)
娱仔、映射文件(*.hbm.xml)
和數(shù)據(jù)庫配置文件(*.properties/*.cfg.xml)
沐飘,它們各自的作用如下:
- 映射類
(*.java)
:它是描述數(shù)據(jù)庫表的結(jié)構(gòu),表中的字段在類中被描述成屬性牲迫,將來就可以實現(xiàn)把表中的記錄映射成為該類的對象了耐朴。 - 映射文件
(*.hbm.xml)
:它是指定數(shù)據(jù)庫表和映射類之間的關(guān)系,包括映射類和數(shù)據(jù)庫表的對應關(guān)系盹憎、表字段和類屬性的對應關(guān)系筛峭。 - 數(shù)據(jù)庫配置文件
(*.properties/*.cfg.xml)
:它是指定與數(shù)據(jù)庫連接時需要的連接信息,比如連接哪種數(shù)據(jù)庫陪每、登錄數(shù)據(jù)庫的用戶名影晓、密碼以及連接字符串等。當然還可以把映射類的地址映射信息放在這里檩禾。
接下來讓我們一起走進Hibernate的幾種關(guān)聯(lián)映射關(guān)系:
單向一對一關(guān)聯(lián)映射(one-to-one):
兩個對象之間一對的關(guān)系挂签,例如:Person(人)- IdCard(身份證)
有兩種策略可以實現(xiàn)一對一的關(guān)聯(lián)映射:
- 主鍵關(guān)聯(lián):即讓兩個對象具有相同的主鍵值,以表明它們之間的一一對應的關(guān)系盼产;數(shù)據(jù)庫表不會有額外的字段來維護它們之間的關(guān)系饵婆,僅通過表的主鍵來關(guān)聯(lián)。如下圖:
注意:需要在Person.hbm.xml映射文件中配置one-to-one
標簽戏售,如下:
<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC
"-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<hibernate-mapping>
<class name="com.nnngu.Person" table="t_person">
<id name="id">
<!-- 采用foreign生成策略侨核,foreign會取得關(guān)聯(lián)對象的標識 -->
<generator class="foreign">
<!-- property只關(guān)聯(lián)對象 -->
<param name="property">idCard</param>
</generator>
</id>
<property name="name"/>
<!-- one-to-one指示hibernate如何加載其關(guān)聯(lián)對象,默認根據(jù)主鍵加載
也就是拿到關(guān)系字段值灌灾,根據(jù)對端的主鍵來加載關(guān)聯(lián)對象
-->
<one-to-one name="idCard" constrained="true"/>
</class>
</hibernate-mapping>
- 唯一外鍵關(guān)聯(lián):外鍵關(guān)聯(lián)搓译,本來是用于多對一的配置,但是加上唯一的限制之后(采用
<many-to-one>
標簽來映射锋喜,指定多的一端unique為true些己,這樣就限制了多的一端的多重性為一),也可以用來表示一對一關(guān)聯(lián)關(guān)系嘿般,其實它就是多對一的特殊情況轴总。如下圖:
需要在Person.hbm.xml映射文件中配置many-to-one
標簽,并指定unique為true博个,如下:
<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC
"-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<hibernate-mapping>
<class name="com.nnngu.Person" table="t_person">
<id name="id">
<generator class="native">
<!-- property只關(guān)聯(lián)對象 -->
<param name="property">idCard</param>
</generator>
</id>
<property name="name"/>
<many-to-one name="idCard" unique="true"/>
</class>
</hibernate-mapping>
注意:因為一對一的主鍵關(guān)聯(lián)映射擴展性不好,當我們的需要發(fā)生改變想要將其變?yōu)橐粚Χ嗟臅r候變無法操作了功偿,所以我們遇到一對一關(guān)聯(lián)的時候經(jīng)常會采用唯一外鍵關(guān)聯(lián)來解決問題盆佣,而很少使用一對一主鍵關(guān)聯(lián)往堡。
單向多對一關(guān)聯(lián)映射(many-to-one):
多對一關(guān)聯(lián)映射原理:在多的一端加入一個外鍵,指向一的一端共耍,如下圖:
關(guān)鍵映射代碼——在多的一端加入如下標簽映射:
<many-to-one name="group" column="groupid"/>
單向一對多關(guān)聯(lián)映射(one-to-many):
一對多關(guān)聯(lián)映射和多對一關(guān)聯(lián)映射原理是一致的虑灰,都是在多的一端加入一個外鍵,指向一的一端痹兜。如下圖(學生和班級):
注意:它與多對一的區(qū)別是維護的關(guān)系不同
- 多對一維護的關(guān)系是:多指向一的關(guān)系穆咐,有了此關(guān)系,加載多的時候可以將一加載上來字旭。
- 一對多維護的關(guān)系是:一指向多的關(guān)系对湃,有了此關(guān)系,在加載一的時候可以將多加載上來遗淳。
關(guān)鍵映射代碼——在一的一端加入如下標簽映射:
<set name="students">
<key column="classesid"/>
<one-to-many class="com.nnngu.Student"/>
</set>
單向多對多映射(many-to-many):
多對多關(guān)聯(lián)映射需要新增加一張表才完成基本映射拍柒,如下圖:
關(guān)鍵映射代碼——可以在User的一端加入如下標簽映射:
<set name="roles" table="t_user_role">
<key column="user_id"/>
<many-to-many class="com.nnngu.Role" column="role_id"/>
</set>
雙向一對一關(guān)聯(lián)映射:
對比單向一對一映射,需要在IdCard也加入<one-to-one>
標簽屈暗。示意圖如下:
雙向一對一主鍵映射關(guān)鍵映射代碼——在IdCard端新加入如下標簽映射:
<one-to-one name="person"/>
雙向一對一唯一外鍵映射關(guān)鍵映射代碼——在IdCard端新加入如下標簽映射:
<one-to-one name="person"property-ref="idCard"/>
注意:一對一唯一外鍵關(guān)聯(lián)雙向采用<one-to-one>
標簽映射拆讯,必須指定<one-to-one>
標簽中的property-ref屬性為關(guān)系字段的名稱
雙向一對多關(guān)聯(lián)映射(非常重要):
采用雙向一對多關(guān)聯(lián)映射的目的主要是為了解決單向一對多關(guān)聯(lián)的缺陷。
雙向一對多關(guān)聯(lián)的映射方式:
- 在一的一端的集合上采用
<key>
標簽养叛,在多的一端加入一個外鍵 - 在多的一端采用
<many-to-one>
標簽
注意:<key>
標簽和<many-to-one>
標簽加入的字段要保持一致种呐,否則會產(chǎn)生數(shù)據(jù)混亂。
在Classes的一端加入如下標簽映射:
<set name="students"inverse="true">
<key column="classesid"/>
<one-to-many class="com.nnngu.Student"/>
</set>
在Student的一端加入如下標簽映射:
<many-to-one name="classes" column="classesid"/>
了解inverse屬性:
- inverse屬性可以用在一對多和多對多雙向關(guān)聯(lián)上弃甥,inverse屬性默認為false爽室,為false表示本端可以維護關(guān)系,如果inverse為true潘飘,則本端不能維護關(guān)系肮之,會交給另一端維護關(guān)系,本端失效卜录。所以一對多關(guān)聯(lián)映射我們通常在多的一端維護關(guān)系戈擒,讓一的一端失效。
- inverse是控制方向上的反轉(zhuǎn)艰毒,只影響存儲筐高。
雙向多對多關(guān)聯(lián)映射:
雙向的目的就是為了兩端都能將對方加載上來,和單向多對多的區(qū)別就是雙向需要在兩端都加入標簽映射丑瞧,需要注意的是:
- 生成的中間表名稱必須一樣
- 生成的中間表中的字段必須一樣
Role(角色)端關(guān)鍵映射代碼:
<set name="users" table="t_user_role">
<key column="role_id"/>
<many-to-many class="com.nnngu.User" column="user_id"/>
</set>
User(用戶)端關(guān)鍵映射代碼:
<set name="roles" table="t_user_role">
<key column="user_id"/>
<many-to-many class="com. nnngu.Role" column="role_id"/>
</set>
總結(jié)
對于上面的七種關(guān)聯(lián)映射柑土,最重要的就是一對多的映射,因為它更貼近我們的現(xiàn)實生活绊汹,比如:教室和學生就可以是典型的一對多的關(guān)系稽屏,而我們開發(fā)軟件的目的之一就是為了解決一些生活中重復性問題,把那些重復的問題交給計算機來幫助我們完成西乖,從而提高我們的工作效率狐榔。