双向一对多映射
双向 1 到 n 和 双向 n 到 1 是完全相同的2中情形。

Customer类的java代码
这里Customer类多了一个orders集合成员变量,用来保存order。

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
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
package com.mamh.hibernate.demo.entities;

import java.util.HashSet;
import java.util.Set;

public class Customer {
private Integer customerId;
private String customerName;

//这里必须是接口类型。需要初始化。
private Set<Order> orders = new HashSet<Order>();



public Customer() {
}

public Customer(String name) {
this.customerName = name;
}


public Integer getCustomerId() {
return customerId;
}

public void setCustomerId(Integer customerId) {
this.customerId = customerId;
}

public String getCustomerName() {
return customerName;
}

public void setCustomerName(String customerName) {
this.customerName = customerName;
}

public Set<Order> getOrders() {
return orders;
}

public void setOrders(Set<Order> orders) {
this.orders = orders;
}

@Override
public String toString() {
return "Customer{" +
"customerId=" + customerId +
", customerName='" + customerName + '\'' +
'}';
}
}

Order类的java代码

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
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
package com.mamh.hibernate.demo.entities;



public class Order {
private Integer orderId;
private String orderName;

//
private Customer customer;

public Integer getOrderId() {
return orderId;
}

public void setOrderId(Integer orderId) {
this.orderId = orderId;
}

public String getOrderName() {
return orderName;
}

public void setOrderName(String orderName) {
this.orderName = orderName;
}

public Customer getCustomer() {
return customer;
}

public void setCustomer(Customer customer) {
this.customer = customer;
}

@Override
public String toString() {
return "Order{" +
"orderId=" + orderId +
", orderName='" + orderName + '\'' +
", customer=" + customer +
'}' + '\n';
}
}

Order类的映射文件,

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
<hibernate-mapping package="com.mamh.hibernate.demo.entities">

<class name="Order" table="hb_order" schema="atguigu">
<id name="orderId">
<column name="hb_order_id" sql-type="int(11)"/>
<generator class="native"/>
</id>
<property name="orderName" type="string">
<column name="hb_order_name"/>
</property>

<!-- 映射多对一的关联关系 property不再试用这个多对一的关系了
name是多这一端关联的那个一那一端属性名称
class的类全名
column是多的一端这边数据表的一个列名,一般是外键
-->
<many-to-one name="customer" class="Customer" column="customer_id"/>


</class>
</hibernate-mapping>

Customer类的映射文件
这里和上一篇文件的代码的区别就是这里customer的映射多了一个set节点

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
<hibernate-mapping package="com.mamh.hibernate.demo.entities">

<class name="Customer" table="hb_customer" schema="atguigu">
<id name="customerId">
<column name="hb_customer_id" sql-type="int(11)"/>
<generator class="native"/>
</id>
<property name="customerName" type="string">
<column name="hb_customer_name"/>
</property>

<set name="orders" table="hb_order">
<key column="customer_id"/>
<one-to-many class="Order"/>
</set>
</class>
</hibernate-mapping>

测试保存

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
@Test
public void testManyToOneSave() {
//双向关联关系
Customer customer = new Customer("ccccccccccccccc");
Order order1 = new Order();
order1.setOrderName("order 1111111111");
Order order2 = new Order();
order2.setOrderName("order 2222222222");
order1.setCustomer(customer);
order2.setCustomer(customer);

customer.getOrders().add(order1);
customer.getOrders().add(order2);
//先保存customer,然后保存order。
session.save(customer);
//执行save操作
session.save(order1);
session.save(order2);
}

先保存customer,后保存order。

1
2
3
4
5
6
7
8
9
10
11
12
13
Hibernate: 
insert into atguigu.hb_customer (hb_customer_name) values (?)
Hibernate:
insert into atguigu.hb_order (hb_order_name, customer_id) values (?, ?)
Hibernate:
insert into atguigu.hb_order (hb_order_name, customer_id) values (?, ?)
=destroy=
Hibernate:
update atguigu.hb_order set customer_id=? where hb_order_id=?
Hibernate:
update atguigu.hb_order set customer_id=? where hb_order_id=?

Process finished with exit code 0

先保存customer,后保存order。
从中看到 多了2条update语句。应为1的一端和n的一端都维护这个关联关系,所以会多出这2个update语句。

在hibernate中可以设置iverse属性来决定有哪一方来维护关联关系。建议设置inverse=true来使1的一端放弃维护关联关系。

如果是先保存order,然后保存customer情况又如何呢?会有4个update语句的。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
Hibernate: 
insert into atguigu.hb_order (hb_order_name, customer_id) values (?, ?)
Hibernate:
insert into atguigu.hb_order (hb_order_name, customer_id) values (?, ?)
Hibernate:
insert into atguigu.hb_customer(hb_customer_name) values(?)
=destroy=
Hibernate:
update atguigu.hb_order set hb_order_name=?, customer_id=? where hb_order_id=?
Hibernate:
update atguigu.hb_order set hb_order_name=?, customer_id=? where hb_order_id=?
Hibernate:
update atguigu.hb_order set customer_id=? where hb_order_id=?
Hibernate:
update atguigu.hb_order set customer_id=? where hb_order_id=?

Process finished with exit code 0

查询操作

1
2
3
4
5
6
7
8
9
10
11
12
@Test
public void testOneToManyGet() {
//对多的一端的集合使用延迟加载
Customer customer = (Customer) session.get(Customer.class, 1);
//返回的集合类型是hibernate内置的一个类型,改类型具有延迟加载和存放代理对象功能
System.out.println(customer.getOrders().getClass());

//也是可能会抛出懒加载LazyInitializationException异常。
session.close();

System.out.println(customer.getOrders().size());
}
1
2
3
4
5
6
7
8
9
10
11
Hibernate: 
select
customer0_.hb_customer_id as hb1_2_0_,
customer0_.hb_customer_name as hb2_2_0_
from
atguigu.hb_customer customer0_
where
customer0_.hb_customer_id=?

Customer{customerId=1, customerName='bbbbbbbbbbbbbbbb'}
class org.hibernate.collection.internal.PersistentSet

更新操作

1
2
3
4
5
6
@Test
public void testOneToManyUpdate() {
Customer customer = (Customer) session.get(Customer.class, 1);
customer.getOrders().iterator().next().setOrderName("d22");

}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
Hibernate: 
select
customer0_.hb_customer_id as hb1_2_0_,
customer0_.hb_customer_name as hb2_2_0_
from
atguigu.hb_customer customer0_
where
customer0_.hb_customer_id=?
Hibernate:
select
orders0_.customer_id as customer3_2_1_,
orders0_.hb_order_id as hb1_1_,
orders0_.hb_order_id as hb1_3_0_,
orders0_.hb_order_name as hb2_3_0_,
orders0_.customer_id as customer3_3_0_
from atguigu.hb_order orders0_
where orders0_.customer_id=?

=destroy=
Hibernate:
update atguigu.hb_order set hb_order_name=?, customer_id=? where hb_order_id=?


Process finished with exit code 0

set节点元素的iverse属性

1
2
3
4
5
<!--通常inverse设置为true,指定有多的那一端来维护关联关系。-->
<set name="orders" table="hb_order" inverse="true">
<key column="customer_id"/>
<one-to-many class="Order"/>
</set>

级联删除cascade=”delete”

1
2
3
4
<set name="orders" table="hb_order" inverse="true" cascade="delete">
<key column="customer_id"/>
<one-to-many class="Order"/>
</set>
1
2
3
4
<set name="orders" table="hb_order" inverse="true" cascade="delete-orphan">
<key column="customer_id"/>
<one-to-many class="Order"/>
</set>

级联保存

1
2
3
4
<set name="orders" table="hb_order" inverse="true" cascade="save-update">
<key column="customer_id"/>
<one-to-many class="Order"/>
</set>

开发时不建议使用这种级联,建议使用手动操作。

set元素的order by属性,在查询时候进行排序,使用的表的字段名。

1
2
3
4
<set name="orders" table="hb_order" inverse="true"   order-by="hb_order_id">
<key column="customer_id"/>
<one-to-many class="Order"/>
</set>
1
2
3
4
5
6
7
8
9
Hibernate: 
select
order0_.hb_order_id as hb1_3_0_,
order0_.hb_order_name as hb2_3_0_,
order0_.customer_id as customer3_3_0_
from
atguigu.hb_order order0_
where
order0_.hb_order_id=?