Hibernate关系映射
一对多关系映射
数据库:在多的一方添加外键来描述关联关系。
实体对象:在一的一方,增加一个集合用来存放多的一方。在多的一方添加一个一的一方的属性。
映射文件配置:
User.hbm.xml1
2
3
4
5
6
7
8
9
10
11<!--
set代表用的什么集合
name代表多的一方的集合的属性名
-->
<set name="carSet">
<!--
key:多的一方的外键名称
-->
<key column="user_id"></key>
<one-to-many class="pojo.Car"></one-to-many>
</set>
Car.hbm.xml1
2
3
4
5
6<!--
name:一的一方的属性名
class:一的一方的类全路径
colum:表中的外键外键名称
-->
<many-to-one name="user" class="pojo.User" column="user_id"></many-to-one>
编写测试代码:1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30@Test
public void test_HiernateYinshe(){
Session session = HibernateUtils.openSession();
Transaction tx = session.beginTransaction();
User user = new User();
user.setName("cl");
user.setPassword("123456");
Car car1 = new Car();
car1.setCar_name("byd");
car1.setColor("red");
Car car2 = new Car();
car2.setCar_name("baoma");
car2.setColor("blue");
//建立关系
user.getCarSet().add(car1);
user.getCarSet().add(car2);
car1.setUser(user);
car2.setUser(user);
session.save(user);
// 以下两句在测试只保存一方时注释
session.save(car1);
session.save(car2);
tx.commit();
session.close();
}
通过观察控制台,会发现控制台输出了三条insert语句和两条update语句。
既然两个对象以及进行了双向关联,那我们只保存一方是否可以呢?
将上面的测试代码中保存Car的两条语句注释。会报一下错误:
这样保存是不行的,无论是从哪一方保存都会报错:瞬时对象异常。一个持久化对象关联了一个瞬时态对象。
如果我们只想保存一个方向,那么我们可以使用Hibernate的级联操作。
首先要确定我们要保存的的主控方式哪一方,用户拥有车,所以用户是主控方。我们需要在用户的映射文件中进行以下配置。1
2
3
4<set name="carSet" cascade="save-update">
<key column="user_id" ></key>
<one-to-many class="pojo.Car"></one-to-many>
</set>
当我们在一方配置了级联配置后,保存时会将其级联的对象也保存在数据库。此时运行测试代码,会发现还是三条insert和两条update语句。因为在Car中还会进行维护外键的操作。其实这是没必要的了。所以我们必须选择一方放弃维护关系。
我们选择User放弃维护,因为一个老师要记住所有学生是比较困难的,但是让学生记住老师确是很容易的。
我们再修改User.hbm.xml1
2
3
4
5
6
7<!--
inverse默认值为false,代表不放弃维护。
-->
<set name="carSet" cascade="save-update" inverse="true">
<key column="user_id" ></key>
<one-to-many class="pojo.Car"></one-to-many>
</set>
此时再执行测试代码。会发现只剩下了三条insert语句
- 区分cascade和inverse
cascade强调的是操作一个对象时,是否操作其关联对象。
inverse强调的是外键的维护权
多对多
数据库:通过一张中间表来描述其对应关系。
实体对象:在两个实体类中都创建一个集合来代表拥有的另一方。
User.hbm.xml配置1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16<!--
name:关联的另一方的集合名称
table:中间表的名称
cascade:级联维护相关对象
-->
<set name="roleSet" table="tb_user_role" cascade="save-update">
<!--
colum:当前对象在中间表的外键名称
-->
<key column="user_id"></key>
<!--
class:关联另一方的类的全路径。
colum:关联的另一方在中间表的外键
-->
<many-to-many class="pojo.Role" column="role_id"></many-to-many>
</set>
Role.hbm.xml1
2
3
4
5
6
7<!--
inverse:多对多的关系映射中必须要有一方放弃维护外键。
-->
<set name="userSet" table="tb_user_role" inverse="true">
<key column="role_id"></key>
<many-to-many class="pojo.User" column="user_id"></many-to-many>
</set>
我们很容易就发现多对多的两方的映射文件差不多。
加载映射配置后编写测试代码。1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29@Test
public void test_many2Many(){
Session session = HibernateUtils.openSession();
Transaction tx = session.beginTransaction();
User user1 = new User("u1","u1");
User user2 = new User("u2","u2");
Role role1 = new Role("前台");
Role role2 = new Role("人事");
Role role3 = new Role("助理");
//建立关系,如果建立了双向关系,一定要有一方放弃外键维护。
user1.getRoleSet().add(role1);
user1.getRoleSet().add(role2);
user2.getRoleSet().add(role1);
user2.getRoleSet().add(role3);
role1.getUserSet().add(user1);
role1.getUserSet().add(user2);
role2.getUserSet().add(user1);
role3.getUserSet().add(user2);
session.save(user1);
session.save(user2);
tx.commit();
session.close();
}
在多对多的关系映射中,进行了双向维护,此时必须有一方需要放弃维护。