时间:2017-1-20 16:28
——一对多配置
1、第一步:创建实体类
* 客户实体
* 订单实体
示例代码:
/**
* 客户实体
* @author WYC
*
*/
public class Customer {
private Integer cid;
private String name;
// 一个客户有多个订单
// 拥有哪些订单
private Set<Order> orders = new HashSet<Order>();
set() / get()...
}
/**
* 订单实体
* @author WYC
*
*/
public class Order {
private Integer oid;
private String addr;
// 订单属于某一个客户
private Customer customer;
set() / get()...
}
2、第二步:建立映射
1)Customer的映射
<hibernate-mapping>
<class name="com.wyc.hibernate3.demo2.Customer" table="customer">
<id name="cid" column="cid">
<generator class="native"/>
</id>
<property name="cname" column="cname" length="20"/>
<!-- 配置映射 -->
<!-- 因为属性是一个集合,所以需要配置集合 -->
<!-- name:Customer对象中关联对象的属性名称 -->
<set name="orders">
<!-- key标签中的column用来描述一对多关系中多的一方的外键的名称 -->
<key column="cid"></key>
<!-- 配置一个<one-to-many>,用来指定多的一方的实体类 -->
<one-to-many class="com.wyc.hibernate3.demo2.Order"/>
</set>
</class>
</hibernate-mapping>
2)Order的映射
<hibernate-mapping>
<class name="com.wyc.hibernate3.demo2.Order" table="order_table">
<id name="oid" column="oid">
<generator class="native"/>
</id>
<property name="addr" column="addr" length="50"/>
<!-- 配置映射 -->
<!-- <many-to-one>标签
name:关联对象的属性名称
column:外键的名称
class:关联对象类的全路径
-->
<many-to-one name="customer" column="cid" class="com.wyc.hibernate3.demo2.Customer" />
</class>
</hibernate-mapping>
one-to-many和many-to-one中的column必须一致,否则会创建两个外键。
3、第三步:将映射放到核心配置文件中
——一对多级联保存
级联:操作当前对象的时候,关联的对象如何处理?
1、通常情况下如果想要向数据库插入数据,需要每个对象都要save一次,例如:
public class HibernateDemo2 {
@Test
// 向客户表插入一个客户,在订单表中插入两个订单
public void fun1() {
Session session = HibernateUtils.openSession();
Transaction tx = session.beginTransaction();
/*
* 定义一个客户
*/
Customer customer = new Customer();
customer.setCname("张三");
/*
* 定义两个订单
*/
Order order1 = new Order();
order1.setAddr("奎文区");
Order order2 = new Order();
order2.setAddr("高新区");
/*
* 建立关系
*/
order1.setCustomer(customer);
order2.setCustomer(customer);
customer.getOrders().add(order1);
customer.getOrders().add(order2);
session.save(customer);
session.save(order1);
session.save(order2);
tx.commit();
session.close();
}
}
2、能否只保存其中一个?从而完成保存两条数据
可以使用级联保存。
级联保存的方向性:
* 保存客户时选择级联订单(在Customer中配置级联)
* 保存订单的时候选择级联客户。(在Order中配置级联)
不能直接save()其中一个持久态对象,否则会抛出异常:org.hibernate.TransientObjectException
3、级联保存示例代码
/*
* 保存订单,同时级联客户
* 当保存订单时,需要关联Customer对象,所以需要在many-to-one上进行配置一个属性:
* cascade="save-update",表示在保存或更新时会级联操作
*/
public void fun4(){
Session session = HibernateUtils.openSession();
Transaction tx = session.beginTransaction();
/*
* 定义一个客户
*/
Customer customer = new Customer();
customer.setCname("张三");
/*
* 定义一个订单
*/
Order order1 = new Order();
order1.setAddr("奎文区");
/*
* 建立关系
*/
order1.setCustomer(customer);
customer.getOrders().add(order1);
/*
* 只保存一方
*/
session.save(order1);
tx.commit();
session.close();
}
/*
* 保存客户,同时级联订单
* 当保存客户时,需要关联Set集合,所以需要在Set集合上进行配置一个属性:
* cascade="save-update",表示在保存或更新时会级联操作
*/
public void fun3(){
Session session = HibernateUtils.openSession();
Transaction tx = session.beginTransaction();
/*
* 定义一个客户
*/
Customer customer = new Customer();
customer.setCname("张三");
/*
* 定义一个订单
*/
Order order1 = new Order();
order1.setAddr("奎文区");
/*
* 建立关系
*/
order1.setCustomer(customer);
customer.getOrders().add(order1);
/*
* 只保存一方
*/
session.save(customer);
tx.commit();
session.close();
}
——一对多级联删除
1、不配置级联删除的情况下:
示例代码:
/*
* 如果不配置级联删除,会将外键置为null,然后再删除记录
*/
public void fun5(){
Session session = HibernateUtils.openSession();
Transaction tx = session.beginTransaction();
/*
* 删除客户
* 如果想要级联删除,则必须先查询再删除
*/
Customer customer = (Customer) session.get(Customer.class, 1);
session.delete(customer);
tx.commit();
session.close();
}
2、配置级联删除的情况下,删除客户的时候级联删除订单:
需要在Customer.hbm.xml的<set>标签上配置cascade="delete",如果cascade有多个值,可以用逗号隔开。
示例代码:
/*
* 级联删除
*/
public void fun6(){
Session session = HibernateUtils.openSession();
Transaction tx = session.beginTransaction();
/*
* 级联删除:先查询,再删除
*/
/*
* 删除客户时级联删除订单
* 在<set>标签中配置cascade="delete"
*/
Customer customer = (Customer) session.get(Customer.class, 1);
session.delete(customer);
/*
* 删除订单时级联删除客户
* 需要在Order.hbm.xml中的many-to-one中配置cascade="delete"
*/
Order order = (Order) session.get(Order.class, 1);
session.delete(order);
tx.commit();
session.close();
}
——cascade取值
1、none
不使用级联,是默认值。
2、save-update
保存或更新时级联。
3、delete
删除时级联。
4、all
除了孤儿删除以外所有的操作都会级联。
5、delete-orphan
孤儿删除(孤子删除)
仅限于一对多,因为只有一对多的时候才有主从(父子)关系存在。
一的一方是主(父)方。
多的一方是从(子)方。
当一个客户与某个订单解除了关系时,相当于把订单的外键置为null,订单就没有了所属客户了,那么就会将这种记录删除。
删除没有外键的记录。
6、all-delete-orphan
包含了孤儿删除的所有级联操作。
7、孤儿删除示例代码:
/*
* 孤儿删除
* 在Customer.hbm.xml中<set>标签上配置cascade="delete-orphan"
*/
public void fun7(){
Session session = HibernateUtils.openSession();
Transaction tx = session.beginTransaction();
/*
* 让2号客户与2号订单解除关系
*/
Customer customer = (Customer) session.get(Customer.class, 2);
Order order = (Order) session.get(Order.class, 2);
// 将该客户对应的其中某一订单删除后,该订单的外键就是null了
customer.getOrders().remove(order);
tx.commit();
session.close();
}
——双向维护 - 产生多余SQL
配置inverse="true",在哪一端配置,配置的那一端就放弃了外键的维护权。
示例代码:
/*
* 双向维护:自动更新数据库,会产生多余的SQL
* 双方都有维护外键的能力,要想不产生多余SQL,必须让其中一方放弃外间的维护权:<set inverse="true">
* 一般情况下都是“多”的一方维护外键关系
*/
public void fun8(){
Session session = HibernateUtils.openSession();
Transaction tx = session.beginTransaction();
/*
* 将3号客户的订单改为1号客户的订单
*/
Customer customer = (Customer) session.get(Customer.class, 1);
Order order = (Order) session.get(Order.class, 3);
/*
* 持久态对象如果发生变化会自动更新数据库
* 会发送两条update语句
*/
customer.getOrders().add(order);
order.setCustomer(customer);
tx.commit();
session.close();
}
——cascade和inverse的区别
cascade:操作关联对象
inverse:控制外键的维护
示例代码:
/*
* 区分cascade和inverse
*
* 在Customer.hbm.xml中配置:<set name="orders" cascade="save-update" inverse="true" >
*/
public void fun9(){
Session session = HibernateUtils.openSession();
Transaction tx = session.beginTransaction();
Customer customer = new Customer();
customer.setCname("张三");
Order order = new Order();
order.setAddr("奎文");
// 客户关联订单
customer.getOrders().add(order);
/*
* 客户是否保存到数据库:保存
* 订单是否保存到数据库:保存,因为设置了cascade="save-update",但是订单的外键是null
* 因为在Customer中设置了inverse="true",说明外键不属于Customer来维护
* 只有在插入订单时,才会产生外键
*/
session.save(customer);
tx.commit();
session.close();
}
——多对多的配置
1、学生实体类
public class Student {
private Integer sid;
private String sname;
private Set<Course> courses = new HashSet<Course>();
@Override
public String toString() {
return "Student [sid=" + sid + ", sname=" + sname + ", courses=" + courses + "]";
}
public Set<Course> getCourses() {
return courses;
}
public void setCourses(Set<Course> courses) {
this.courses = courses;
}
public Integer getSid() {
return sid;
}
public void setSid(Integer sid) {
this.sid = sid;
}
public String getSname() {
return sname;
}
public void setSname(String sname) {
this.sname = sname;
}
}
2、课程实体类
public class Course {
private Integer cid;
private String cname;
private Set<Student> students = new HashSet<Student>();
public Integer getCid() {
return cid;
}
public void setCid(Integer cid) {
this.cid = cid;
}
public String getCname() {
return cname;
}
public void setCname(String cname) {
this.cname = cname;
}
public Set<Student> getStudents() {
return students;
}
public void setStudents(Set<Student> students) {
this.students = students;
}
}
3、Student.hbm.xml
<?xml version="1.0" encoding="UTF-8"?>
<hibernate-mapping>
<class name="com.wyc.hibernate3.demo3.Student" table="student">
<id name="sid" column="sid">
<generator class="native"></generator>
</id>
<property name="sname" column="sname" length="20" />
<!-- 配置关联映射 -->
<!-- 多对多时存在中间表,table属性写中间表的名称,两个类中的table必须一致,否则生成多个中间表 -->
<set name="courses" table="stu_cour">
<!-- key标签中的column写本类在中间表中的外键字段 -->
<key column="sid" />
<!-- many-to-many中的class是另一方类的全路径,column表示另一方类在中间表中外键的名称 -->
<many-to-many class="com.wyc.hibernate3.demo3.Course" column="cid"></many-to-many>
</set>
</class>
</hibernate-mapping>
4、Course.hbm.xml
<?xml version="1.0" encoding="UTF-8"?>
<hibernate-mapping>
<class name="com.wyc.hibernate3.demo3.Course" table="course">
<id name="cid" column="cid">
<generator class="native"></generator>
</id>
<property name="cname" column="cname" length="20" />
<!-- 配置与学生关联的映射 -->
<set name="students" table="stu_cour" inverse="true" >
<key column="cid" />
<many-to-many class="com.wyc.hibernate3.demo3.Student" column="sid"/>
</set>
</class>
</hibernate-mapping>
5、将映射配置文件添加到核心配置文件中
——多对多的保存操作
如果在多对多的情况下进行保存,则必须有一方放弃主键维护,不然会导致主键重复。
通常是主动方来维护主键,比如学生选课,学生来维护主键。
需要在Course.hbm.xml中添加<set inverse="true">来指定Course放弃维护主键。
public class HibernateDemo3 {
@Test
/*
* 保存学生和课程 为学生选择一些课程
*/
public void fun1() {
Session session = HibernateUtils.openSession();
Transaction tx = session.beginTransaction();
// 创建学生
Student student1 = new Student();
student1.setSname("张三");
Student student2 = new Student();
student2.setSname("李四");
// 创建课程
Course course1 = new Course();
course1.setCname("Java");
Course course2 = new Course();
course2.setCname("Android");
// 张三选择1号课程和2号课程
student1.getCourses().add(course1);
student1.getCourses().add(course2);
course1.getStudents().add(student1);
course2.getStudents().add(student1);
// 李四选1号课程
student2.getCourses().add(course1);
course1.getStudents().add(student2);
// 执行保存
session.save(student1);
session.save(student2);
session.save(course1);
session.save(course2);
tx.commit();
session.close();
}
}
——多对多级联保存
/*
* 级联操作:保存学生,关联课程
* 在Student.hbm.xml中配置cascade="save-update"
*/
public void fun2() {
Session session = HibernateUtils.openSession();
Transaction tx = session.beginTransaction();
// 创建学生
Student student = new Student();
student.setSname("王五");
// 创建课程
Course course = new Course();
course.setCname("PHP");
student.getCourses().add(course);
course.getStudents().add(student);
session.save(student);
tx.commit();
session.close();
}
——删除中间表信息
获取中间表后将记录从集合中删除即可。
/*
* 删除1号学生的选课信息
*/
public void fun3() {
Session session = HibernateUtils.openSession();
Transaction tx = session.beginTransaction();
// 查询1号学生
Student student = (Student) session.get(Student.class, 1);
// 查询1号课程
Course course = (Course) session.get(Course.class, 1);
// 删除选课信息
student.getCourses().remove(course);
tx.commit();
session.close();
}
——总结
1、一对一的配置
* 在多的一方:<many-to-one>
* 在一的一方:<set> <key /> <one-to-many> </set>
2、多对多的配置
* <set> <key /> <many-to-many /> </set>
在多对多关系的情况下,需要有一方放弃外键维护权。
3、级联操作
* save-update
* delete
* all
* delete-orphan(孤儿删除)
* all-delete-orphan
4、inverse
放弃外键维护权
通常在一的一方放弃。
- hibernate有关联关系删除子表时可能会报错,可以用个clear避免错误
//清除子表数据 public SalesSet removeSalesSetDistributor(SalesSet salesSet ){ List<SalesSetDistributor& ...
- Hibernate之关联关系映射(一对一主键映射和一对一外键映射)
1:Hibernate的关联关系映射的一对一外键映射: 1.1:第一首先引包,省略 1.2:第二创建实体类: 这里使用用户信息和身份证信息的关系,用户的主键编号既可以做身份证信息的主键又可以做身份证信 ...
- Hibernate JPA 关联关系
Hibernate JPA 关联关系: 使用cascade做级联操作(只有在满足数据库约束时才会生效): CascadeType.PERSIST: 级联保存,只有调用persist()方法,才会级联保 ...
- Hibernate 一对一关联关系
双向一对一关联关系: 域模型: 例如,部门只有一个部门经理,一个经理也只能管理一个部门.即,Department 中有一个Manager的引用,Manager 中又有一个Department 的引用. ...
- 框架之 hibernate之关联关系映射
案例:完成CRM的联系人的保存操作 需求分析 1. 因为客户和联系人是一对多的关系,在有客户的情况下,完成联系人的添加保存操作 技术分析之Hibernate的关联关系映射之一对多映射(重点) 1. J ...
- Hibernate的关联关系映射
技术分析之Hibernate的关联关系映射之一对多映射(重点) 1. JavaWEB中一对多的设计及其建表原则 2. 先导入SQL的建表语句 ...
- Hibernate —— 映射关联关系
一.映射多对一关联关系. 1.单向的多对一 (1)以 Customer 和 Order 为例:一个用户可以发出多个订单,而一个订单只能属于一个客户.从 Order 到 Customer 是多对一关联关 ...
- Hibernate 实体关联关系映射【转】
Hibernate关联关系映射目录│ ├─单向关联│ ├─ 一对一外键单向关联│ ├─ 一对一主键单向关联│ ├─ 一对一连接表单向关联│ ├─ 一对多外键单向关联│ ├─ 一对多 ...
- Hibernate笔记——关联关系配置(一对多、一对一和多对多)
原文:http://www.cnblogs.com/otomedaybreak/archive/2012/01/20/2327695.html ============================ ...
- Hibernate三 关联关系
Hibernate的关联映射 客观世界中很少有对象是独立存在的,比如我们可以通过某个老师获取该老师教的所有学生,我们也可以通过某个学生获得教他的对应的老师,实体之间的互相访问就是关联关系.在Hiber ...
随机推荐
- Leetcode:面试题28. 对称的二叉树
Leetcode:面试题28. 对称的二叉树 Leetcode:面试题28. 对称的二叉树 Talk is cheap . Show me the code . /** * Definition fo ...
- P4774-屠龙勇士-扩展中国剩余定理
屠龙勇士 很久很久以前,巨龙突然出现,带来了灾难带走公主又消失不见.王国十分危险,世间谁最勇敢,一位英雄出现-- 学习于该大佬博客 那么你就是这位英雄,不过不同的是,你面对的是一群巨龙,虽然巨龙都不会 ...
- Python自动化测试面试题-用例设计篇
目录 Python自动化测试面试题-经验篇 Python自动化测试面试题-用例设计篇 Python自动化测试面试题-Linux篇 Python自动化测试面试题-MySQL篇 Python自动化测试面试 ...
- Spring Security OAuth2 远程命令执行漏洞(CVE-2016-4977)
影响版本: 2.0.0-2.0.9 1.0.0-1.0.5 poc地址 https://github.com/vulhub/vulhub/blob/master/spring/CVE-2016-497 ...
- python编写DDoS攻击脚本
python编写DDoS攻击脚本 一.什么是DDoS攻击 DDoS攻击就是分布式的拒绝服务攻击,DDoS攻击手段是在传统的DoS攻击基础之上产生的一类攻击方式.单一的DoS攻击一般是采用一对一方式的, ...
- Feign实战技巧篇
介绍Feign在项目中的正确打开方式 看了上一期Feign远程调用的小伙伴可能会问:阿鉴,你不是说上一期讲的是Feign的99%常用方式吗?怎么今天还有正确打开方式一说呀? 阿鉴:是99%的常用方式, ...
- CentOS后台服务管理类
目录 一.service 后台服务管理(临时,只对当前有效) 二.chkconfig 设置后台服务的自启配置(永久) 三.CentOS7 后添加的命令:systemctl 一.service 后台服务 ...
- Esxi安装Kali2并开启远程桌面
Kali安装 登录Vmware Esxi页面,选择"创建/注册虚拟机",步骤和创建其它Linux主机类似(Esxi的安装和介绍可以参考上一篇文章) 不同的地方是,客户机操作系统版本 ...
- 关于Feign、Jackson、RabbitMQ、Jrebel插件的开发中遇到的问题
在工作实际开发中需要开发一个消息模块对外提供统一的接口feign调用提供消息加载到MQ队列的服务,采用泛型的形式. 刚开始搭建好之后,正好需要做一个全局的日志添加到zuul网关中,通过网关feign ...
- ES6继承和ES5继承是完全一样的么?
继承方式 ES5 prototype 继承 通过原型链(构造函数 + [[prototype]])指向实现继承. (备注:后续__proto__我都会写成[[prototype]]这种形式) 子类的 ...