Hibernate在實現ORM功能的時候主要用到的文件有:映射類(*.java)、映射文件(*.hbm.xml)和數據庫配置文件(*.properties/*.cfg.xml),它們各自的作用如下。
映射類(*.java):它是描述數據庫表的結構,表中的字段在類中被描述成屬性,將來就可以實現把表中的記錄映射成爲該類的對象了。
映射文件(*.hbm.xml):它是指定數據庫表和映射類之間的關係,包括映射類和數據庫表的對應關係、表字段和類屬性類型的對應關係以及表字段和類屬性名稱的對應關係等。
數據庫配置文件(*.properties/*.cfg.xml):它是指定與數據庫連接時需要的連接信息,比如連接哪種數據庫、登錄數據庫的用戶名、登錄密碼以及連接字符串等。當然還可以把映射類的地址映射信息放在這裏。
接下來讓我們就一起走進Hibernate的七種映射關係:
1、 單向一對一關聯映射(one-to-one):
兩個對象之間一對的關係,例如:Person(人)-IdCard(身份證)
有兩種策略可以實現一對一的關聯映射:
*主鍵關聯:即讓兩個對象具有相同的主鍵值,以表明它們之間的一一對應的關係;數據庫表不會有額外的字段來維護它們之間的關係,僅通過表的主鍵來關聯。如下圖:
*唯一外鍵關聯:外鍵關聯,本來是用於多對一的配置,但是加上唯一的限制之後(採用<many-to-one>標籤來映射,指定多的一端unique爲true,這樣就限制了多的一端的多重性爲一),也可以用來表示一對一關聯關係,其實它就是多對一的特殊情況。如下圖:
注意:因爲一對一的主鍵關聯映射擴展性不好,當我們的需要發生改變想要將其變爲一對多的時候變無法操作了,所以我們遇到一對一關聯的時候經常會採用唯一外鍵關聯來解決問題,而很少使用一對一主鍵關聯。
2、 單向多對一關聯映射(many-to-one):
多對一關聯映射原理:在多的一端加入一個外鍵,指向一的一端,如下圖:
關鍵映射代碼——在多的一端加入如下標籤映射:
- <many-to-one name="group" column="groupid"/>
3、 單向一對多關聯映射(one-to-many):
一對多關聯映射和多對一關聯映射原理是一致的,都是在多的一端加入一個外鍵,指向一的一端。如下圖(學生和班級):
注意:它與多對一的區別是維護的關係不同
*多對一維護的關係是:多指向一的關係,有了此關係,加載多的時候可以將一加載上來
*一對多維護的關係是:一指向多的關係,有了此關係,在加載一的時候可以將多加載上來
關鍵映射代碼——在一的一端加入如下標籤映射:
- <set name="students">
- <key column="classesid"/>
- <one-to-many class="com.hibernate.Student"/>
- </set>
缺陷:因爲多的一端Student不知道Classes的存在(也就是Student沒有維護與Classes的關係)所以在保存Student的時候關係字段classesid是爲null的,如果將該關係字段設置爲非空,則將無法保存數據,常用解決辦法是改用雙向關聯映射,參見6。
4、 單向多對多映射(many-to-many):
多對多關聯映射新增加一張表才完成基本映射,如下圖:
關鍵映射代碼——可以在User的一端加入如下標籤映射:
- <set name="roles" table="t_user_role">
- <key column="user_id"/>
- <many-to-many class="com.hibernate.Role" column="role_id"/>
- </set>
5、 雙向一對一關聯映射:
對比單向一對一映射,需要在IdCard加入<one-to-one>標籤,它不影響,隻影響加載。如下圖:
雙向一對一主鍵映射關鍵映射代碼——在IdCard端新加入如下標籤映射:
- <one-to-one name="person"/>
雙向一對一唯一外鍵映射關鍵映射代碼——在IdCard端新加入如下標籤映射:
- <one-to-one name="person"property-ref="idCard"/>
注意:一對一唯一外鍵關聯雙向採用<one-to-one>標籤映射,必須指定<one-to-one>標籤中的property-ref屬性爲關係字段的名稱
6、 雙向一對多關聯映射(非常重要):
採用一對多雙向關聯映射的目的主要是爲了主要是爲了解決一對多單向關聯的缺陷而不是需求驅動的。
一對多雙向關聯的映射方式:
* 在一的一端的集合上採用<key>標籤,在多的一端加入一個外鍵
* 在多的一端採用<many-to-one>標籤
注意:<key>標籤和<many-to-one>標籤加入的字段保持一直,否則會產生數據混亂
關鍵映射代碼:
在Classes的一端加入如下標籤映射:
- <set name="students"inverse="true">
- <key column="classesid"/>
- <one-to-many class="com.hibernate.Student"/>
- </set>
在Student的一端加入如下標籤映射:
- <many-to-one name="classes" column="classesid"/>
註釋:inverse屬性
* inverse屬性可以用在一對多和多對多雙向關聯上,inverse屬性默認爲false,爲false表示本端可以維護關係,如果inverse爲true,則本端不能維護關係,會交給另一端維護關係,本端失效。所以一對多關聯映射我們通常在多的一端維護關係,讓一的一端失效。
* inverse是控制方向上的反轉,隻影響存儲
7、 雙向多對多關聯映射:
雙向的目的就是爲了兩端都能將對方加載上來,和單向多對多的區別就是雙向需要在兩端都加入標籤映射,需要注意的是:
* 生成的中間表名稱必須一樣
* 生成的中間表中的字段必須一樣
Role(角色)端關鍵映射代碼:
- <set name="users" table="t_user_role">
- <key column="role_id"/>
- <many-to-many class="com.hibernate.User" column="user_id"/>
- lt;/set>
User(用戶)端關鍵映射代碼:
- <set name="roles" table="t_user_role">
- <key column="user_id"/>
- <many-to-many class="com. hibernate.Role" column="role_id"/>
- lt;/set>
總結:對於上面這七種關聯映射中,最重要的就是一對多的映射,因爲它更貼近我們的現實生活,比如:教室和學生就可以是典型的一對多的關係,而我們開發軟件的目的之一就是爲了解決一些生活中重複性問題,把那些重複的問題交給計算機幫助我們完成,從而來提高我們的工作效率。一句話:生活離開不開編程,編程更離不開生活。