之前我们对User与Room作了单向的多对一以及反过来的一对多关联,我们也可以让User与Room彼此参考,形成双向关联,就User与Room对象,具体来说,就是将程序如下设计:
User.java
package onlyfun.caterpillar;
public class User {
private long id;
private String name;
private Room room;
public long getId() {
return id;
}
public void setId(long id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Room getRoom() {
return room;
}
public void setRoom(Room room) {
this.room = room;
}
}
Room.java
package onlyfun.caterpillar;
import java.util.*;
public class Room {
private long id;
private String address;
private Set users = new HashSet();
public long getId() {
return id;
}
public void setId(long id) {
this.id = id;
}
public String getAddress() {
return address;
}
public void setAddress(String address) {
this.address = address;
}
public Set getUsers() {
return users;
}
public void setUsers(Set users) {
this.users = users;
}
}
而其对应的映射文件如下,首先是User.hbm.xml:
User.hbm.xml
<!---->
<!---->
PUBLIC "-//Hibernate/Hibernate Mapping DTD//EN"
"http://hibernate.sourceforge.net/hibernate-mapping-2.0.dtd">
<hibernate-mapping></hibernate-mapping>
<class table="USER" name="onlyfun.caterpillar.User"></class>
<id name="id" unsaved-value="0" column="USER_ID"></id>
<generator class="increment"></generator>
<property name="name"></property>
<column></column>
<many-to-one name="room" span=""></many-to-one>
column="ROOM_ID"
class="onlyfun.caterpillar.Room"/>
再来是Room.hbm.xml:
Room.hbm.xml
<!---->
<!---->
PUBLIC "-//Hibernate/Hibernate Mapping DTD//EN"
"http://hibernate.sourceforge.net/hibernate-mapping-2.0.dtd">
<hibernate-mapping></hibernate-mapping>
<class table="ROOM" name="onlyfun.caterpillar.Room"></class>
<id name="id" unsaved-value="0" column="ROOM_ID"></id>
<generator class="increment"></generator>
<property name="address" type="string"></property>
<key column="ROOM_ID"></key>
<one-to-many class="onlyfun.caterpillar.User"></one-to-many>
这就形成了User与Room之间的双向关联映像,我们可以使用以下的程序进行测试:
HibernateTest.java
import onlyfun.caterpillar.*;
import net.sf.hibernate.*;
import net.sf.hibernate.cfg.*;
public class HibernateTest {
public static void main(String[] args) throws HibernateException {
SessionFactory sessionFactory = new Configuration().configure().buildSessionFactory();
Room room = new Room();
room.setAddress("NTU-M8-419");
User user1 = new User();
user1.setName("bush");
User user2 = new User();
user2.setName("bush");
/*
* 因为没有设定inverser,所以只须从parent维护即可
*/
//user1.setRoom(room);
//user2.setRoom(room);
room.getUsers().add(user1);
room.getUsers().add(user2);
Session session = sessionFactory.openSession();
Transaction tx= session.beginTransaction();
session.save(room);
tx.commit();
session.close();
sessionFactory.close();
}
}
基本上就数据的储存来说,这样就已经足够,但这样的设计会有效能问题,显然的,这个程序将Room与User之间的关联交由Room来维持,就Room 而言,它要先储存自已,然后储存其所包括的多个User,之后再对每一个User更新(update)对自己(Room)的关联,具体而言,这个程序必须实行以下的SQL:
Hibernate: insert into ROOM (address, ROOM_ID) values (?, ?)
Hibernate: insert into USER (NAME, ROOM_ID, USER_ID) values (?, ?, ?)
Hibernate: insert into USER (NAME, ROOM_ID, USER_ID) values (?, ?, ?)
Hibernate: update USER set ROOM_ID=? where USER_ID=?
Hibernate: update USER set ROOM_ID=? where USER_ID=?
就Room而言,它并不知道其所包括的User是不是一个已储存的对象,或者即使为已储存对象,也不知道USER表格 上的ROOM_ID是不是参考至ROOM表格的ROOM_ID上,所以它必须针对自己所包括的User对象一个个进行更新,以确保USER表格上的 ROOM_ID是指向自己。
如果将关联的维护交给User的话会比较容易,因为每个User都对应至一个Room,在储存时并用像Room一样必须对Set中的每个对象作检查,为 了将关联的维护交给User,我们可以在Room.hbm.xml中的修改,加上inverse="true",表示将关联的维护「反过来」交给User作:
Room.java
<key column="ROOM_ID"></key>
<one-to-many class="onlyfun.caterpillar.User"></one-to-many>
由于将关联的维护交给User来作了,所以我们必须在储存时,明确的将Room设定给User,也就是说,必须这样作:
/*
* 因为有user维护关联,所以必须呼叫setRoom
*/
user1.setRoom(room);
user2.setRoom(room);
room.getUsers().add(user1);
room.getUsers().add(user2);
这比不加上inverse="true"设定时多了个指定的动作,您必须多键几个字,所带来的是效率上的增加,Hibernate的持久层管理员会先储存Room,然后储存User,如此就可以省去之前再进行更新的动作,具体来说,就是会执行以下的SQL:
Hibernate: insert into ROOM (address, ROOM_ID) values (?, ?)
Hibernate: insert into USER (NAME, ROOM_ID, USER_ID) values (?, ?, ?)
Hibernate: insert into USER (NAME, ROOM_ID, USER_ID) values (?, ?, ?)
与先前不同的是,由于关联交给了User维护,所以这次Room不用一一更新USER以确定每个ROOM_ID都指向自已。
如果指定了inverse="true",而不确实的将Room指定给User会如何?那么User与Room会各自储存,但彼此没有关联,也就是User将不会参考至Room,USER表格的ROOM_ID将为null,例如:
mysql> select * from USER;
+---------+------+---------+
| USER_ID | NAME | ROOM_ID |
+---------+------+---------+
| 1 | bush | NULL |
+---------+------+---------+
mysql> select * from ROOM;
+---------+------------+
| ROOM_ID | address |
+---------+------------+
| 1 | NTU-M8-419 |
+---------+------------+
作个总结,在设立双向关联时,关联由多对一中「多」的哪一方维护,会比由「一」的哪一方维护来的方便,在Hibernate可以藉由inverse来设定,不设定inverse基本上也可以运行,但是效能会较差。
设定了inverse,必须要明确的设定双方的参考,以这个主题的例子,Room要设定给User,而User也要知道Room的存在,这比不设定 inverse需要键入较多的字,但从另一方面,比较符 合程序设计的直觉(单看User与Room类别,两者要互相参考时,本来就要明确设定)。
分享到:
相关推荐
#### 双向关联与inverse设定 在实体之间存在双向关联的情况下,需要正确设置`inverse`属性,以避免循环引用的问题。正确设置`inverse`可以确保Hibernate在处理关联关系时的行为符合预期。 #### 一对一与多对多实体...
- **双向关联与inverse设定**: - 在多对多、一对多等关联中管理引用方向。 - **延迟加载** (`LazyInitialization`): - 延迟加载关联对象,提高应用性能。 - **Session管理**: - 开启、关闭`Session`,管理事务...
#### 双向关联与inverse设定 - **双向关联**:表示两个实体之间相互引用的情况。 - **inverse设定**:通过`inverse="true"`属性指定由哪一方负责维护关系,以避免并发问题。 #### 一对一实体映射 - **描述**:一种...
#### 双向关联与inverse设定 - **定义**:双向关联是指两个实体类之间存在相互引用的情况。 - **inverse设定**:通过`inverse="true"`指定哪个方向负责关联的维护。 #### 一对一实体映射 - **定义**:表示两个实体...
在一个双向一对多关联中,通常设定一方为“拥有”关系的一方,另一方为“被拥有”的一方。inverse属性用于指定哪一侧不负责维护关联关系。例如,如果将区设为inverse=true,那么在添加或删除街道时,不需要通过区...
7.2 映射一对多双向关联关系 7.2.1 元素的inverse属性 7.2.2 级联删除 7.2.3 父子关系 7.3 映射一对多双向自身关联关系 7.4 改进持久化类 7.5 小结 7.6 思考题 第8章 通过Hibernate操纵对象(上) ...
7.2 映射一对多双向关联关系 7.2.1 元素的inverse属性 7.2.2 级联删除 7.2.3 父子关系 7.3 映射一对多双向自身关联关系 7.4 改进持久化类 7.5 小结 7.6 思考题 第8章 通过Hibernate操纵对象(上) ...
7.2 映射一对多双向关联关系 7.2.1 元素的inverse属性 7.2.2 级联删除 7.2.3 父子关系 7.3 映射一对多双向自身关联关系 7.4 改进持久化类 7.5 小结 7.6 思考题 第8章 通过Hibernate操纵对象(上) ...
7.2 映射一对多双向关联关系 7.2.1 元素的inverse属性 7.2.2 级联删除 7.2.3 父子关系 7.3 映射一对多双向自身关联关系 7.4 改进持久化类 7.5 小结 7.6 思考题 第8章 通过Hibernate操纵对象(上) ...
12、写Hibernate的一对多和多对一双向关联的orm配置? 122 9、hibernate的inverse属性的作用? 122 13、在DAO中如何体现DAO设计模式? 123 14、spring+Hibernate中委托方案怎么配置? 123 15、spring+Hibernate中委托...
12、写Hibernate的一对多和多对一双向关联的orm配置? 122 9、hibernate的inverse属性的作用? 122 13、在DAO中如何体现DAO设计模式? 123 14、spring+Hibernate中委托方案怎么配置? 123 15、spring+Hibernate中委托...
12、写Hibernate的一对多和多对一双向关联的orm配置? 122 9、hibernate的inverse属性的作用? 122 13、在DAO中如何体现DAO设计模式? 123 14、spring+Hibernate中委托方案怎么配置? 123 15、spring+Hibernate中委托...
12、写Hibernate的一对多和多对一双向关联的orm配置? 122 9、hibernate的inverse属性的作用? 122 13、在DAO中如何体现DAO设计模式? 123 14、spring+Hibernate中委托方案怎么配置? 123 15、spring+Hibernate中委托...
12、写Hibernate的一对多和多对一双向关联的orm配置? 122 9、hibernate的inverse属性的作用? 122 13、在DAO中如何体现DAO设计模式? 123 14、spring+Hibernate中委托方案怎么配置? 123 15、spring+Hibernate中...
12、写Hibernate的一对多和多对一双向关联的orm配置? 134 9、hibernate的inverse属性的作用? 134 13、在DAO中如何体现DAO设计模式? 134 14、spring+Hibernate中委托方案怎么配置? 134 15、spring+Hibernate中委托...
12、写Hibernate的一对多和多对一双向关联的orm配置? 122 9、hibernate的inverse属性的作用? 122 13、在DAO中如何体现DAO设计模式? 123 14、spring+Hibernate中委托方案怎么配置? 123 15、spring+Hibernate中委托...