上篇博文描述了Hibernate - 单向多对一关联关系映射,本篇博文继续学习单向一对多关系映射。
这里Customer:Order= 1:N,外键保存在Order表中。
【1】修改Customer和Order
Customer修改如下:
public class Customer {
private Integer customerId;
private String customerName;
private Set<Order> orders;
//拥有属性orders
public Set<Order> getOrders() {
return orders;
}
public void setOrders(Set<Order> orders) {
this.orders = orders;
}
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;
}
@Override
public String toString() {
return "Customer [customerId=" + customerId + ", customerName=" + customerName + ", orders=" + orders + "]";
}
}
Customer.hbm.xml修改如下:
<hibernate-mapping package="com.jane.model">
<class name="Customer" table="CUSTOMERS">
<id name="customerId" type="java.lang.Integer">
<column name="CUSTOMER_ID" />
<generator class="native" />
</id>
<property name="customerName" type="java.lang.String">
<column name="CUSTOMER_NAME" default="null" />
</property>
<!--
name="orders"表示一的一端拥有多的那端的属性;
key节点中属性column="customer_id"表示外键(数据库多的一端拥有的)
-->
<set name="orders" table="ORDERS">
<key column="customer_id"></key>
<one-to-many class="Order"/>
</set>
</class>
</hibernate-mapping>
<key>
元素设定本持久化类在Set对应表中的外键列名。如上值Customer类在ORDERS表中的外键列名–customer_id。
Order修改如下:
public class Order {
private Integer orderId;
private String orderName;
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;
}
@Override
public String toString() {
return "Order [orderId=" + orderId + ", orderName=" + orderName+"]";
}
}
Order.hbm.xml如下:
<hibernate-mapping package="com.jane.model">
<class name="Order" table="ORDERS">
<id name="orderId" type="java.lang.Integer">
<column name="ORDER_ID" />
<generator class="native" />
</id>
<property name="orderName" type="java.lang.String">
<column name="ORDER_NAME" default="null" />
</property>
</class>
</hibernate-mapping>
生成的数据库表结构如下所示:
//Customers表
CREATE TABLE `customers` (
`CUSTOMER_ID` int(11) NOT NULL AUTO_INCREMENT,
`CUSTOMER_NAME` varchar(255) DEFAULT NULL,
PRIMARY KEY (`CUSTOMER_ID`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
//Orders表
CREATE TABLE `orders` (
`ORDER_ID` int(11) NOT NULL AUTO_INCREMENT,
`ORDER_NAME` varchar(255) DEFAULT NULL,
`customer_id` int(11) DEFAULT NULL,
PRIMARY KEY (`ORDER_ID`),
KEY `FK1nbewmmir6psft27yfvvmwpfg` (`customer_id`),
CONSTRAINT `FK1nbewmmir6psft27yfvvmwpfg` FOREIGN KEY (`customer_id`) REFERENCES `customers` (`CUSTOMER_ID`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
可以发现,无论是多对一还是一对多,外键都是多的一端数据表所持有。
单向多对一中,以多的一端为主,在多的一端xml中使用<many-to-one/>
进行配置。
单向一对多中,以一的一端为主,在一的一端xml中使用<one-to-many/>
进行配置。
【2】代码测试
① 单向一对多持久化
和单向多对一持久化不同的是,单向 1-n 关联关系执行保存时, 一定会多出 UPDATE 语句。因为 n 的一端在插入时不会同时插入外键列。
@Test
public void testOneToManySave(){
Customer customer = new Customer();
customer.setCustomerName("AAA");
customer.setOrders(new HashSet<>());
Order order1 = new Order();
order1.setOrderName("O-JJ-1");
Order order2 = new Order();
order2.setOrderName("O-JJ-2");
System.out.println(customer);
//建立关联关系
customer.getOrders().add(order1);
customer.getOrders().add(order2);
session.save(customer);
session.save(order1);
session.save(order2);
}
测试结果如下:
Hibernate:
insert
into
CUSTOMERS
(CUSTOMER_NAME)
values
(?)
Hibernate:
insert
into
ORDERS
(ORDER_NAME)
values
(?)
Hibernate:
insert
into
ORDERS
(ORDER_NAME)
values
(?)
Hibernate:
update
ORDERS
set
customer_id=?
where
ORDER_ID=?
Hibernate:
update
ORDERS
set
customer_id=?
where
ORDER_ID=?
② 单向一对多获取对象
默认对关联的多的一方使用懒加载的加载策略,只有在使用的时候才会进行查询。
测试代码如下:
@Test
public void testOneToManyGet(){
Customer customer = session.get(Customer.class, 1);
System.out.println(customer);
System.out.println(customer.getOrders().size());
}
测试结果如下:
Hibernate:
select
customer0_.CUSTOMER_ID as CUSTOMER1_0_0_,
customer0_.CUSTOMER_NAME as CUSTOMER2_0_0_
from
CUSTOMERS customer0_
where
customer0_.CUSTOMER_ID=?
Hibernate:
select
orders0_.customer_id as customer3_2_0_,
orders0_.ORDER_ID as ORDER_ID1_2_0_,
orders0_.ORDER_ID as ORDER_ID1_2_1_,
orders0_.ORDER_NAME as ORDER_NA2_2_1_
from
ORDERS orders0_
where
orders0_.customer_id=?
Customer [customerId=1, customerName=AAA, orders=[Order [orderId=1, orderName=O-JJ-1], Order [orderId=2, orderName=O-JJ-2]]]
2
③ 单向一对多更新操作
代码如下:
@Test
public void testUpdate(){
Customer customer = session.get(Customer.class, 1);
customer.getOrders().iterator().next().setOrderName("O-XXX-10");
}
测试结果如下:
Hibernate:
select
customer0_.CUSTOMER_ID as CUSTOMER1_0_0_,
customer0_.CUSTOMER_NAME as CUSTOMER2_0_0_
from
CUSTOMERS customer0_
where
customer0_.CUSTOMER_ID=?
Hibernate:
select
orders0_.customer_id as customer3_2_0_,
orders0_.ORDER_ID as ORDER_ID1_2_0_,
orders0_.ORDER_ID as ORDER_ID1_2_1_,
orders0_.ORDER_NAME as ORDER_NA2_2_1_
from
ORDERS orders0_
where
orders0_.customer_id=?
Hibernate:
update
ORDERS
set
ORDER_NAME=?
where
ORDER_ID=?
单独更新CustomerName如下:
@Test
public void testUpdate(){
Customer customer = session.get(Customer.class, 1);
customer.setCustomerName("CC");
System.out.println(customer.getCustomerName());
System.out.println(customer);
}
测试结果如下:
Hibernate:
select
customer0_.CUSTOMER_ID as CUSTOMER1_0_0_,
customer0_.CUSTOMER_NAME as CUSTOMER2_0_0_
from
CUSTOMERS customer0_
where
customer0_.CUSTOMER_ID=?
CC
Hibernate:
select
orders0_.customer_id as customer3_2_0_,
orders0_.ORDER_ID as ORDER_ID1_2_0_,
orders0_.ORDER_ID as ORDER_ID1_2_1_,
orders0_.ORDER_NAME as ORDER_NA2_2_1_
from
ORDERS orders0_
where
orders0_.customer_id=?
Customer [customerId=1, customerName=CC, orders=[Order [orderId=1, orderName=O-XXX-10], Order [orderId=2, orderName=O-JJ-2]]]
Hibernate:
update
CUSTOMERS
set
CUSTOMER_NAME=?
where
CUSTOMER_ID=?
④ 单向一对多删除操作
默认情况下, 若删除 1 的一端, 则会先把关联的 n 的一端的外键置空, 然后进行删除。
测试代码如下:
@Test
public void testOneToManyDel(){
Customer customer = session.get(Customer.class,1);
session.delete(customer);
}
测试结果如下:
//先查询
Hibernate:
select
customer0_.CUSTOMER_ID as CUSTOMER1_0_0_,
customer0_.CUSTOMER_NAME as CUSTOMER2_0_0_
from
CUSTOMERS customer0_
where
customer0_.CUSTOMER_ID=?
//更新Order表的外键Customer_ID 为null
Hibernate:
update
ORDERS
set
customer_id=null
where
customer_id=?
//删除Customers
Hibernate:
delete
from
CUSTOMERS
where
CUSTOMER_ID=?
综上可知,只有在持久化操作和删除操作时,单向一对多和单向多对一有所不同,在查找和更新时没有什么区别。
博文是基于XML进行讲解,那么注解版的如何使用呢?
参考博文:注解版的单向一对多