Hibernate一对多(多对一)关联关系
上一篇博文总结了 Hibernate 的一对一的关联关系, 包括基于主键的单向一对一, 基于外键的单向一对一, 基于外键的双向一对一.
下面咱们说一下 Hibernate 的一对多关联关系.
其实一对多和多对一是一样的, 一对多反过来想就是多对一了.
Hibernate的一对多可分为:
1. 单向一对多.
2. 双向一对多.
OneByOne
一: 单向一对多
准备工作:
咱们以 客户(Customer) 和 订单(Order) 的例子来说, 一个客户可以有多个订单, 但是一个订单只能属于一个客户, 这就构成了一对多的关系.
1. 建立持久化类:
Customer类:
package com.single.many2one;
public class Customer {
private Integer id;
private String name;
public Customer() {
super();
}
public Customer(String name) {
super();
this.name = name;
}
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
Order类:
package com.single.many2one;
public class Order {
private Integer id;
private String name;
private Customer customer;
public Order() {
super();
}
public Order(String name, Customer customer) {
super();
this.name = name;
this.customer = customer;
}
public Customer getCustomer() {
return customer;
}
public void setCustomer(Customer customer) {
this.customer = customer;
}
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
2. 建立对应的映射文件
Customer类映射文件:
<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<hibernate-mapping>
<class name="com.single.many2one.Customer" table="CUSTOMERS">
<id name="id" type="java.lang.Integer">
<column name="ID" />
<generator class="identity" />
</id>
<property name="name" type="java.lang.String">
<column name="NAME" />
</property>
</class>
</hibernate-mapping>
Order类映射文件:
<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<hibernate-mapping package="com.single.many2one">
<class name="Order" table="ORDERS">
<id name="id" type="java.lang.Integer">
<column name="ID" />
<generator class="identity" />
</id>
<property name="name" type="java.lang.String">
<column name="NAME" />
</property>
<many-to-one name="customer" class="Customer">
<column name="CUSTOMER_ID" />
</many-to-one>
</class>
</hibernate-mapping>
3. 把映射文件加入到 Hibernate 的主配置文件( hibernate.cfg.xml )里
4. 建立单元测试类
package com.single.many2one;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.Transaction;
import org.hibernate.cfg.Configuration;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
public class TestHibernate {
private SessionFactory sessionFactory;
private Session session;
private Transaction transaction;
@Before
public void init(){
sessionFactory = new Configuration().configure().buildSessionFactory();
session = sessionFactory.openSession();
transaction = session.beginTransaction();
}
@After
public void distory(){
transaction.commit();
session.close();
sessionFactory.close();
}
}
在上面的持久化类中, 订单(Order)中有对客户(Customer)的引用, 而客户(Customer)不知道订单(Order)的存在.
1. 测试保存数据:
@Test
public void testInsert(){
Customer customer = new Customer("Mike");
Order order1 = new Order("O-Mike-01", customer);
Order order2 = new Order("O-Mike-02", customer);
Order order3 = new Order("O-Mike-03", customer);
// 保存的时候要先保存 1 的一端, 然后保存 n 的一端
// 这样可以避免多出 n 条 update 语句
session.save(customer);
session.save(order1);
session.save(order2);
session.save(order3);
}
为什么反过来保存会多出 n 条update语句, 很简单, 维护关联关系. 如果先保存 order 这个时候, 外键还没有值, 最后插入Customer的时候, 外键有值了, 就会发送update语句来更新Order表的外键值.
2. 测试查询数据
@Test
public void testQuery(){
// 默认使用懒加载模式, 注意懒加载异常
Order order = session.get(Order.class, 1);
System.out.println(order.getName());
System.out.println(order.getCustomer().getClass().getName());
}
默认使用懒加载, 如果想不适用懒加载可以在 <many-to-one> 标签中使用 lazy="false", 来禁用懒加载.
3. 测试删除数据:
@Test
public void testDelete(){
// 想想都知道, 有外键约束, 肯定不会删除成功.
Customer customer = session.get(Customer.class, 1);
session.delete(customer);
}
4. 测试更新数据:
@Test
public void testUpdte(){
// 一般不会出现什么问题
// 作为程序员这样说, 实在是太不负责任了
// 是我掌握的不够. 以后会继续深入研究的.
Customer customer = session.get(Customer.class, 1);
customer.setName("Jerry");
session.update(customer);
}
二: 双向一对多
准备工作:
咱们还是以客户(Customer)和订单(Order)的例子来说, 与上面不同的是, 现在Customer类中有一个集合(Set)来存放Order对象.
1. 建立持久化类:
Customer类:
package com.doubles.one2many;
import java.util.HashSet;
import java.util.Set;
public class Customer {
private Integer id;
private String name;
private Set<Order> orders = new HashSet<>();
public Set<Order> getOrders() {
return orders;
}
public void setOrders(Set<Order> orders) {
this.orders = orders;
}
public Customer() {
super();
}
public Customer(String name) {
super();
this.name = name;
}
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
Order类:
package com.doubles.one2many;
public class Order {
private Integer id;
private String name;
private Customer customer;
public Order() {
super();
}
public Order(String name, Customer customer) {
super();
this.name = name;
this.customer = customer;
}
public Customer getCustomer() {
return customer;
}
public void setCustomer(Customer customer) {
this.customer = customer;
}
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
2. 建立映射文件
Customer的映射文件:
<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<hibernate-mapping package="com.doubles.one2many">
<class name="Customer" table="CUSTOMERS">
<id name="id" type="java.lang.Integer">
<column name="ID" />
<generator class="identity" />
</id>
<property name="name" type="java.lang.String">
<column name="NAME" />
</property>
<!--
在hibernate中通过对 inverse 属性的来决定是由双向关联的哪一方来维护表和表之间的关系.
inverse = false 的为主动方
inverse = true 的为被动方
由主动方负责维护关联关系
在没有设置 inverse=true 的情况下, 父子两边都维护父子关系
在 1-n 关系中, 将 n 方设为主控方将有助于性能改善
(如果要国家元首记住全国人民的名字,不是太可能,但要让全国人民知道国家元首,就容易的多)
在 1-N 关系中,若将 1 方设为主控方会额外多出 update 语句.
插入数据时无法同时插入外键列,因而无法为外键列添加非空约束.
-->
<set name="orders" table="ORDER" inverse="true">
<!--
设定与所关联的持久化类对应的表的外键
column: 指定关联表的外键名, 就是 Order.hbm.xml 中的外键(CUSTOMER_ID)
-->
<key column="CUSTOMER_ID" />
<!--
设定集合属性中所关联的持久化类
class: 指定关联的持久化类的类名
-->
<one-to-many class="Order" />
</set>
</class>
</hibernate-mapping>
Order的映射文件:
<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<hibernate-mapping package="com.doubles.one2many">
<class name="Order" table="ORDERS">
<id name="id" type="java.lang.Integer">
<column name="ID" />
<generator class="identity" />
</id>
<property name="name" type="java.lang.String">
<column name="NAME" />
</property>
<many-to-one name="customer" class="Customer">
<column name="CUSTOMER_ID" />
</many-to-one>
</class>
</hibernate-mapping>
3. 把映射文件加入到 Hibernate 的主配置文件( hibernate.cfg.xml )里
4. 建立单元测试类(略)
1. 测试保存数据:
@Test
public void testInsert() {
Customer customer = new Customer("Jerry");
Order order1 = new Order("O-Jerry-01", customer);
Order order2 = new Order("O-Jerry-02", customer);
Order order3 = new Order("O-Jerry-03", customer);
customer.getOrders().add(order1);
customer.getOrders().add(order2);
customer.getOrders().add(order3);
/*
* 1. 在没有设置 inverse="true" 的情况下
* a). 如果先保存 n 的一端, 再保存 1 的一端, 会多出 6 条update语句.
* b). 如果先保存 1 的一端, 在保存 n 的一端, 会多出 3 条update语句.
* 2. 设置了 inverse="true" 的情况下
* a). 如果先保存 n 的一端, 再保存 1 的一端, 会多出 3 条update语句.
* b). 如果先保存 1 的一端, 再保存 n 的一端, 没有多余的update语句.
*/
session.save(customer);
session.save(order1);
session.save(order2);
session.save(order3);
}
出现 update 语句是因为要维护两个数据表之间的关联关系.
2. 测试删除数据:
@Test
public void testQuery(){
// 默认使用懒加载
Customer customer = session.get(Customer.class, 1);
System.out.println(customer.getName());
System.out.println(customer.getOrders().getClass().getName());
//上一语句打印: org.hibernate.collection.internal.PersistentSet
// 这是 Hibernate内置的类型, 该类型具有延迟加载和存放代理对象的功能.
//可能出现懒加载问题
// 默认使用懒加载
// Order order = session.get(Order.class, 1);
// System.out.println(order.getName());
// System.out.println(order.getCustomer().getClass().getName());
}
3. 测试删除数据(略)
4. 测试更新数据(略)
Customer.hbm.xml中的<set>标签还有很多属性可以选, 比如: order-by="": 值为数据列的某列列名.
Hibernate一对多(多对一)关联关系的更多相关文章
- Hibernate-ORM:12.Hibernate中的多对多关联关系
------------吾亦无他,唯手熟尔,谦卑若愚,好学若饥------------- 本篇博客将讲述Hibernate中的多对多关联关系的操作,准备的篇幅较少,望海涵 一,讲述多对多 多对多的关联 ...
- (转)Hibernate框架基础——多对多关联关系映射
http://blog.csdn.net/yerenyuan_pku/article/details/52756536 多对多关联关系映射 多对多的实体关系模型也是很常见的,比如学生和课程的关系.一个 ...
- Hibernate 一对多自身双向关联关系 用于类别表的实现
分类:一对多自身双向关联关系 Java持久化类: package com.hyy.hibernate.one_to_many.domain; import java.util.HashSet; imp ...
- Hibernate 一对多/多对多
一对多关联(多对一): 一对多关联映射: 在多的一端添加一个外键指向一的一端,它维护的关系是一指向多 多对一关联映射: 咋多的一端加入一个外键指向一的一端,它维护的关系是多指向一 在配置文件中添加: ...
- Hibernate -- 一对多的双向关联关系
示例代码: Customer.java package cn.itcast.many2onedouble; import java.util.HashSet; import java.util.Set ...
- hibernate一对多多对一双向
注意事项:一对多,多对一双向关联,在一的一方的多的getSet集合上的oneToMany上加上mappedBy.告诉hibernate由多的方一来维护关系.这也符合逻辑 ,本来外键就是在加在多的一方. ...
- hibernate 一对多 多对一 关系表 增删改查大礼包ps二级查也有
今天来到混元气功 这货大概的意思就是你中有我 我中有你 ps 这里就要说到维护关系 ps写这个用了我一下午.......也是刚刚好复习到这里 顺便就写写 注意:一般都在多方维护关系,至于是用单向还是用 ...
- Hibernate一对多自关联、多对多关联
今天分享hibernate框架的两个关联关系 多对多关系注意事项 一定要定义一个主控方 多对多删除 主控方直接删除 被控方先通过主控方解除多对多关系,再删除被控方 禁用级联删除 关联关系编辑,不 ...
- Hibernate(6)—— 一对多 和 多对多关联关系映射(xml和注解)总结
俗话说,自己写的代码,6个月后也是别人的代码……复习!复习!复习!涉及的知识点总结如下: One to Many 映射关系 多对一单向外键关联(XML/Annotation) 一对多单向外键关联(XM ...
随机推荐
- iOS开发ARC内存管理
本文的主要内容: ARC的本质 ARC的开启与关闭 ARC的修饰符 ARC与Block ARC与Toll-Free Bridging ARC的本质 ARC是编译器(时)特性,而不是运行时特性,更不是垃 ...
- PAT (Basic Level) Practise:1037. 在霍格沃茨找零钱
[题目链接] 如果你是哈利·波特迷,你会知道魔法世界有它自己的货币系统 —— 就如海格告诉哈利的:“十七个银西可(Sickle)兑一个加隆(Galleon),二十九个纳特(Knut)兑一个西可,很容易 ...
- java.util.NoSuchElementException解决办法
报错代码 public void switchToNewWindow(){ //得到当前句柄 String currentWindow = driver.getWindowHandle(); //得到 ...
- HTML5实现屏幕手势解锁
HTML5实现屏幕手势解锁(转载) https://github.com/lvming6816077/H5lockHow to use? <script type="text/java ...
- JAVA生成TXT日志文件
/** * 生成日志文件(文件的位置在Tomcat的安装路径下) * @param str */ public static void LogForTXT(String str) { try { St ...
- 在package.json里面的script设置环境变量,区分开发及生产环境。注意mac与windows的设置方式不一样
在package.json里面的script设置环境变量,区分开发及生产环境. 注意mac与windows的设置方式不一样. "scripts": { "publish- ...
- Qt 动画框架
最近一个项目中的需要做动画效果,很自然就想起来用qt animation framework .这个框架真的很强大.支持多个动画组合,线性动画,并行动画等.在此总结一下使用该框架一些需要注意的地方: ...
- RESTful API的重磅好伙伴Swagger2
本文将介绍RESTful API的重磅好伙伴Swagger2,它可以轻松的整合到Spring Boot中,并与Spring MVC程序配合组织出强大RESTful API文档. 它既可以减少我们创建文 ...
- 【AT91SAM3S】英倍特串口示例工程05-UART中,串口是怎样初始化的
在这个示例工程的main.c文件中,进入main之后,没有发现串口功能的任何配置.直接使用了printf这个东西进行输出.将软件下载到开发板上之后,在电脑端使用串口软件,可以看板子有数据发来.说明这个 ...
- Spring AOP 完成日志记录
Spring AOP 完成日志记录 http://hotstrong.iteye.com/blog/1330046