個人理解
inverter是hibernate維護關聯關系的配置,也就是說我們必須是雙向關聯關系踩能配置該屬性,在one-to-many注解中有一個
mappedBy屬性用於標記當實體之間是雙向的,作用相當與Inverse屬性,
---------------------------------------------------
Inverse是hibernate雙向關系中的基本概念。inverse的真正作用就是指定由哪一方來維護之間的關聯關系。當一方中指定了“inverse=false”(默認),那么那一方就有責任負責之間的關聯關系,說白了就是hibernate如何生成Sql來維護關聯的記錄!
Hibernate僅僅按照主控方對象的狀態的變化來同步更新數據庫。按照原來的映射文件,people.getAddresses().add(address),即主控方對象的狀態發生了改變,因此數據庫會跟着對象狀態的變化來同步更新數據庫;而address.setPeople(people),即被控方對象的狀態發生了改變,它是不能觸發對象和數據庫的同步更新的。
(實例1):
舉個最簡單的一對多父子關系。那么代碼就寫成:
[java] view plain copy
print?在CODE上查看代碼片派生到我的代碼片
Parent p = new Parent();
Child c = new Child();
c.setParent(p); //維護父子之間關系
p.getChildren().add(c);
session.save(p);
session.flush();
映射文件配置:
[html] view plain copy
print?在CODE上查看代碼片派生到我的代碼片
父親中的關系映射
{set name="children" lazy="true" inverse="true"}
{key column="parent_id"/}
{one-to-many class="test.Child"/}
{/set}
兒子中關系映射
{many-to-one name="parent" column="parent_id" not-null="true"/}
set中inverse="true",說明父子關系只在多的一端(Child)維護。所以只會發出2個insert語句。
注意:{many-to-one}總是設成“inverse=false”的,而且這個屬性在Mapping中是不存在的!
這樣運行的下來的結果就是:
[sql] view plain copy
print?在CODE上查看代碼片派生到我的代碼片
Hibernate: insert into parent (id) values (?)
Hibernate: insert into child (parent_id, id) values (?, ?)
如果將set中的inverse設為true,那么會發出3條sql語句,前2條是insert語句,后1條是update語句用來維護parent和child類的父子關系。
當然,假如c.setParent(p)注釋掉(破壞了父子關系),結果就變成了:
[sql] view plain copy
print?在CODE上查看代碼片派生到我的代碼片
Hibernate: insert into parent (id) values (?)
===================================================
(實例2):
一個Person可以參加多個Event,一個Event有多個Person參加。映射文件如下:
[html] view plain copy
print?在CODE上查看代碼片派生到我的代碼片
<!-- Person.hbm.xml -->
<hibernate-mapping package="events">
<class name="Person" table="person">
<id name="id" column="person_id">
<generator class="native"/>
</id>
<property name="age" length="0"/>
<property name="firstname"/>
<property name="lastname"/>
<set name="events" table="person_event">
<key column="person_id"/>
<many-to-many column="event_id" class="events.Event"/>
</set>
</class>
</hibernate-mapping>
<!-- Event.hbm.xml -->
<hibernate-mapping>
<class name="events.Event" table="events">
<id name="id" column="event_id">
<generator class="native"/>
</id>
<property name="date" column="events_date" type="timestamp"/>
<property name="title" column="events_title"/>
<set name="participants" table="person_event" inverse="true">
<key column="event_id"/>
<many-to-many column="person_id" class="events.Person"/>
</set>
</class>
</hibernate-mapping>
inverse=true的含義: 由雙向關聯另一方維護該關聯,己方不維護該關聯(只能進行查詢操作)。在上述代碼中,由Person方維護該<many-to-many>關系,示例代碼如下(以向Person參與的Event中加入新的Event為例):
[java] view plain copy
print?在CODE上查看代碼片派生到我的代碼片
Session session = HibernateUtil.getSessionFactory().getCurrentSession();
session.beginTransaction();
Person p = (Person) session.load(Person.class, personId);
Event e = (Event) session.load(Event.class, eventId);
p.getEvents().add(e);//執行該代碼時,hibernate會向中間表 person_event中插入person_id和event_id記錄,如果換成e.getParticipants().add(p)的話,該代碼將不會被執行,即hibernate不會向表person_event中插入記錄。
session.getTransaction().commit();
要注意的一點:在雙向關聯的關系中,映射的column(和table)的值要一致(即要用相同的表名和列名),不然設置為inverse="true"的這方將失去這個雙向關系,而變成了一個單向關聯。
二、Inverse和Cascade的比較
Inverse:負責控制關系,默認為false,也就是關系的兩端都能控制,但這樣會造成一些問題,更新的時候會因為兩端都控制關系,於是重復更新。一般來說有一端要設為true。
Cascade:負責控制關聯對象的級聯操作,包括更新、刪除等,也就是說對一個對象進行更新、刪除時,其它對象也受影響,比如我刪除一個對象,那么跟它是多對一關系的對象也全部被刪除。
舉例說明區別:刪除“一”那一端一個對象O的時候,如果“多”的那一端的Inverse設為true,則把“多”的那一端所有與O相關聯的對象外鍵清空;如果“多”的那一端的Cascade設為Delete,則把“多”的那一端所有與O相關聯的對象全部刪除
inverse的意思是反轉,用來設置關系哪一方是擁有者owner,由他來維護這個關系。
在一對多的關系中,包含Set/Collection 類實例是“一”,Set里面包含的類實例則是“多”的一方。可以理解為 Set/Collectin 是代碼中一對多關系的表達,包含Set/Collection的類實例在沒有設置inverse的時候是owner。
inverse="false" 是默認情況,此時沒有反轉,則 Set/Collection 關系由包含它的“一”這一方來維;
inverse="true" 時,表示 Set/Collection 關系由另一方來維護,由不包含這個關系的一方來維護這個關系,所以才稱為“反轉”了。
例如,Parent類和Child類有一個one-to-many的關系,如果要Parent增加一個Child,在inverse="true"時,由Child的一方來維護關系,應該這樣調用:
Child child = new Child();
child.setParent(parent);
此時調用 parent.getChildren().add(child) 是不會生效的。
為了簡化編程,一般的做法是在 Parent 類里面加一個 addChild的方法:
public void addChild( Child child ) {
child.setParent(this);
this.children.add(child);
}
這樣的話,增加一個child只需要調用 addChild 方法就可以了。
追問:
維護關系是什么意思?
追答:
就是指哪一方對關系作出的改動會生效,即引起hibernate執行更新。例如:
child.setParent(parent) 和 parent.getChildren().add(child)中,如果是child一方維護關系的話,則第一個調用生效,如果是parent一方維護關系的話,則第二個調用會生效。