Hibernate入门(三)—— 一对多、多对多关系
一、一对多关系
1.概念
一对多关系是关系型数据库中两个表之间的一种关系。通常在数据库层级中,两表之间是有主外键关系的。在ORM中,如何通过对象描述表之间的关系,是ORM核心。
2.Hibernate的一对多关联映射【重点】
2.1表关系的分析
MySql语句
CREATE TABLE `t_category` (
`cid` int(11) NOT NULL AUTO_INCREMENT,
`cname` varchar(255) DEFAULT NULL,
PRIMARY KEY (`cid`)
);
CREATE TABLE `t_product` (
`pid` int(11) NOT NULL AUTO_INCREMENT,
`pname` varchar(255) DEFAULT NULL,
`price` double DEFAULT NULL,
`cid` int(11) DEFAULT NULL,
PRIMARY KEY (`pid`),
KEY `FKq8yr5sflwtcj3jqp58x0oy7lx` (`cid`),
CONSTRAINT `FKq8yr5sflwtcj3jqp58x0oy7lx` FOREIGN KEY (`cid`) REFERENCES `t_category` (`cid`)
);
2.2创建持久化类
Category.java(一的一方)
public class Category {
private Integer cid;
private String cname;
//在一的一方,用一个集合表示和product的关系
private Set<Product> products = new HashSet<Product>(); 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<Product> getProducts() {
return products;
}
public void setProducts(Set<Product> products) {
this.products = products;
}
}Product.java(多的一方)
public class Product {
private Integer pid;
private String pname;
private double price;
//用一个对象表示,当前商品属于哪个类别
private Category category;
public Integer getPid() {
return pid;
}
public void setPid(Integer pid) {
this.pid = pid;
}
public String getPname() {
return pname;
}
public void setPname(String pname) {
this.pname = pname;
}
public double getPrice() {
return price;
}
public void setPrice(double price) {
this.price = price;
}
public Category getCategory() {
return category;
}
public void setCategory(Category category) {
this.category = category;
} }
2.3创建映射
分类的映射
<hibernate-mapping>
<class name="com.pri.bean.Category" table="t_category">
<!--一,主键属性 -->
<id name="cid" column="cid">
<generator class="native"></generator>
</id>
<!-- 二,其它属性 -->
<property name="cname" column="cname"/> <!-- 三,表示和商品的关系 -->
<!--3.1 set标签的name属性:多的一方的集合的名字 -->
<set name="products">
<!--3.2 key的 column表示多的一方外键名 -->
<key column="cid"/>
<!--3.3 one-to-many的class属性表示多的一方类的全限定名 -->
<one-to-many class="com.pri.bean.Product"/>
</set>
</class>
</hibernate-mapping>商品的映射
<hibernate-mapping>
<class name="com.pri.bean.Product" table="t_product">
<!--一,主键属性 -->
<id name="pid" column="pid">
<generator class="native"></generator>
</id>
<!-- 二,其它属性 -->
<property name="pname" column="pname"/>
<property name="price" column="price"/> <!-- 三,表示和分类的关系 -->
<!--3.1name:一的一方对象的名字
class: 一的一方类的全限定名
column:外键的名字
-->
<many-to-one name="category" class="com.pri.bean.Category" column="cid"/>
</class>
</hibernate-mapping>
2.4将映射添加到配置文件
<!-- 三、加载映射关系配置 -->
<mapping resource="com/pri/bean/Product.hbm.xml"/>
<mapping resource="com/pri/bean/Category.hbm.xml"/>
2.5写代码测试
TestDb
public class TestDb { @Test
public void fun01(){
Session session = HibernateUtils.openSession();
Transaction transaction = session.beginTransaction(); transaction.commit();
session.close();
}
}
3.级联操作
3.1概念
如果我们对某一个表进行了操作,那么也会顺带对关联表进行操作。或者说当对主对象进行某种操作时是也对其关联的从对象也作类似的操作.
eg:如果我们删除了一个公司,那么就得要求,员工表也得把属于这个公司的所有员工也删除掉。
如果我们删除了一个类别, 那么该类别下的商品是否要删除或者不删除只删除外键,那么这样的操作就属于级联操作了.
3.2 级联保存和修改
3.2.1 操作一方级联保存多方【掌握】
保存Category(一的一方)的时候级联保存Product(多的一方)
应用场景: 保存一方的同时也需要保存多方(并且多方的数据比较多). eg: 订单和订单项
<!-- 三、表示和商品的关系 -->
<!-- 3.1 set标签的name属性:多的一方的集合的名字 -->
<set name="products" cascade="save-update"/>
<!-- 3.2 key的column表示多的一方外键名 -->
<key column="cid"/>
<!-- 3.3 one-to-many的class属性表示多的一方类的全限定名 -->
<one-to-many class="com.pri.bean.Product"/>
</set>
/**
* 只保存分类,通过级联把当前分类下的商品也保存
* 配置: 在category.hbm.xml下设置:
* <set cascade="save-update">
*/
@Test
public void fun02(){
Session session = HibernateUtils.openSession();
Transaction transaction = session.beginTransaction(); Category c1 = new Category();
c1.setCname("水果"); Product p1 = new Product();
p1.setPname("苹果");
p1.setPrice(5); //c1和p1 产生关系
c1.getProducts().add(p1);
//p1和c1产生关系
p1.setCategory(c1);
session.save(c1);
//session.save(p1);不需要了,通过级联保存特性自动保存
transaction.commit();
session.close();
}
3.2.2操作多方级联保存一方【了解】
<!--三.表示和分类的关系 -->
<!-- 3.1 name:一的一方对象的名字
class: 一的一方类的全限定名
column:外键的名字
-->
<many-to-one name="category" class="com.pri.bean.Category" column="cid" cascade="save-update"/>
保存Product(多的一方的)的时候级联保存Category(一的一方)
/**
* 只保存商品,通过级联的特性保存商品对应的分类
* 配置: 在product.hbm.xml下设置:
* <many-to-one cascade="save-update"/>
*/
@Test
public void fun03(){
Session session = HibernateUtils.openSession();
Transaction transaction = session.beginTransaction(); Category c1 = new Category();
c1.setCname("水果"); Product p1 = new Product();
p1.setPname("苹果");
p1.setPrice(5); //p1和c1发生关系
p1.setCategory(c1); session.save(p1); //session.save(c1); 不需要了 transaction.commit();
session.close();
}
3.3级联删除
3.3.1删除一方级联删除多方【掌握】
删除Category(一的一方)的时候级联删除Product(多的一方)
场景: 删除一方的时候确保多方的数据没有任何用途的时候的才会用. eg: 公司和员工
实际开发里面很少删除用户的数据. 通常用一个字段标识的
<!-- 三.表示和商品的关系 -->
<!-- 3.1 set标签的name属性:多的一方的集合的名字 -->
<set name="products" cascade="delete">
<!--3.2 key 的column表示多的一方外键名 -->
<key column="cid"/>
<!-- 3.3 one-to-many的class属性表示多的一方类的全限定名 -->
<one-to-many class="com.pri.bean.Product"/>
</set>@Test
//级联删除商品: 删除id为1的类别,级联删除当前类别下的所有商品
//因为删除的是类别,所有在Category.hbm.xml配置:<set name="products" cascade="delete">
public void fun03(){
Session session = HibernateUtils.getCurrentSession();
Transaction transaction = session.beginTransaction(); //先查 id为1的类别
Category category = session.get(Category.class, 1);
session.delete(category);
transaction.commit();
}
3.3.2 删除多方级联删除一方【了解】
删除Product(多的一方)的时候级联删除Category(一的一方)
<!--三.表示和分类的关系 -->
<!-- 3.1 name:一的一方对象的名字
class: 一的一方类的全限定名
column:外键的名字
-->
<many-to-one name="category" class="com.pri.bean.Category" column="cid" cascade="delete"/>
@Test
//级联删除分类: 删除id为1的商品,级联删除这个商品所属的类别(了解)
//把当前id为1商品删除,把这个商品所属的类别删除, 商品表里面该类别其它的商品的记录的外键置为null;
public void fun04(){
Session session = HibernateUtils.getCurrentSession();
Transaction transaction = session.beginTransaction(); //先查 id为1的类别
Product product = session.get(Product.class, 1);
session.delete(product); transaction.commit();
}
4.外键维护
4.1 双向关联产生多余的SQL语句
一旦存在主外键关系,那么外键就由双方对象去维护了, 那么就会造成对这个外键执行了多次操作, 有一次操作其实可以避免的。 也就是说这个外键只要让一个人去维护即可。 外键属于谁,就让谁去维护。
eg:修改产品对应的类别
4.2inverse标签属性
4.2.1概念
inverse
:外键维护,默认为false。代表一方不去维护多方外键。(inverse有反转的意思)
外键属于谁, 谁就负责维护.
4.2.2一方的放弃外键维护
只能在一的一方放弃外键维护
<set inverse="true">
...
</set>EG:
<!-- 三.表示和商品的关系 -->
<!-- 3.1 set标签的name属性:多的一方的集合的名字 -->
<set name="products" cascade="delete" inverse="true">
<!--3.2 key 的column表示多的一方外键名 -->
<key column="cid"/>
<!-- 3.3 one-to-many的class属性表示多的一方类的全限定名 -->
<one-to-many class="com.pri.bean.Product"/>
</set>
/**
* 把苹果(p1)的类别设置为水果(c2)
* 衣服是(c1)
*/
@Test
public void fun02(){
Session session = HibernateUtils.openSession();
Transaction transaction = session.beginTransaction();
//获得苹果
Product p1 = session.get(Product.class, 1);
//获得食物类别
Category c2 = session.get(Category.class, 2); //p1和c2关联
p1.setCategory(c2);
//c2和p1关联
c2.getProducts().add(p1); transaction.commit();
session.close();
}
二、多对多的关系
1.概念
多对多关系是关系数据库中两个表之间的一种数据关系,为了维护这种关系,通常会存在一张中间关系表。两张表都只和关系表间建立主外键关系。
2.Hibernate的多对多关联映射【重点】
2.1表关系的分析
MySql语句
2.2创建实体
Student.java
public class Student { private Integer sid;
private String sname; private Set<Course> courses = new HashSet<Course>();
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;
}
public Set<Course> getCourses() {
return courses;
}
public void setCourses(Set<Course> courses) {
this.courses = courses;
} }
Course.java
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;
} }
2.3创建映射
学生的映射
<hibernate-mapping>
<class name="com.itheima.bean.Student" table="t_student">
<!--一,主键属性 -->
<id name="sid" column="sid">
<generator class="native"></generator>
</id>
<!-- 二,其它属性 -->
<property name="sname" column="sname"/> <!-- 三,表示和课程的关系 -->
<!--3.1 set标签的name属性:当前类中集合的名字
table:第三方表名
-->
<set name="courses" table="s_c_tab">
<!--3.2 key的 column表示当前类在中间表中的外键 -->
<key column="sid" />
<!--3.3 many-to-many表示多对多关系
column:表示另一方在中间表中的外键
class:表示另一方类的全限定名
-->
<many-to-many column="cid" class="com.itheima.bean.Course" ></many-to-many>
</set>
</class>
</hibernate-mapping>课程的映射
<hibernate-mapping>
<class name="com.itheima.bean.Course" table="t_course">
<!--一,主键属性 -->
<id name="cid" column="cid">
<generator class="native"></generator>
</id>
<!-- 二,其它属性 -->
<property name="cname" column="cname"/> <!-- 三,表示和课程的关系 -->
<!--3.1 set标签的name属性:当前类中集合的名字
table:第三方表名
-->
<set name="students" table="s_c_tab">
<!--3.2 key的 column表示当前类在中间表中的外键 -->
<key column="cid"/>
<!--3.3 many-to-many表示多对多关系
column:表示另一方在中间表中的外键
class:表示另一方类的全限定名
-->
<many-to-many column="sid" class="com.itheima.bean.Student"></many-to-many>
</set>
</class>
</hibernate-mapping>
2.4将映射添加到配置文件
<!-- 三.加载映射关系配置 -->
<mapping resource="com/pri/bean/Student.hbm.xml"/>
<mapping resource="com/pri/bean/Course.hbm.xml"/>
2.5写代码测试
保存
/**
* 正常保存
*/
@Test
public void fun01(){
Session session = HibernateUtils.openSession();
Transaction transaction = session.beginTransaction(); Student s1 = new Student();
s1.setSname("张三");
Student s2 = new Student();
s2.setSname("李四"); Course c1 = new Course();
c1.setCname("C语言");
Course c2 = new Course();
c2.setCname("Java");
Course c3 = new Course();
c3.setCname("前端"); //s1选择了c1和c2
s1.getCourses().add(c1);
s1.getCourses().add(c2); //s2选择了c2 c3
s2.getCourses().add(c2);
s2.getCourses().add(c3); //c1被s1选了
c1.getStudents().add(s1);
//c2被s1,s2选了
c2.getStudents().add(s1);
c2.getStudents().add(s2);
//c3被s2选了
c3.getStudents().add(s2);
//如果双向关联,一定要一方放弃主键维护
session.save(s1);
session.save(s2);
session.save(c1);
session.save(c2);
session.save(c3); transaction.commit();
session.close();
}
3.级联操作
3.1级联保存【掌握】
保存Student级联保存Course
<set name="courses" table="s_c_table" cascade="save-update,delete">
<!-- 3.2 key的column表示当前类在中间表的外键 -->
<key column="sid"/>
<!-- 3.3 many-to-many 表示多对对关系
column:表示另一方在中间表中的外键
class:表示另一方类的全限定名
-->
<many-to-many class="com.pri.bean.Course" column="cid"/>
</set>
/**
* 保存Student级联保存Course
* 在student.hbm.xml里面配置:<set name="courses" table="s_c_tab" cascade="save-update">
*/
@Test
public void fun02(){
Session session = HibernateUtils.openSession();
Transaction transaction = session.beginTransaction(); Student s1 = new Student();
s1.setSname("张三");
Student s2 = new Student();
s2.setSname("李四"); Course c1 = new Course();
c1.setCname("C语言");
Course c2 = new Course();
c2.setCname("Java");
Course c3 = new Course();
c3.setCname("前端"); //s1选择了c1和c2
s1.getCourses().add(c1);
s1.getCourses().add(c2); //s2选择了c2 c3
s2.getCourses().add(c2);
s2.getCourses().add(c3); //c1被s1选了
c1.getStudents().add(s1);
//c2被s1,s2选了
c2.getStudents().add(s1);
c2.getStudents().add(s2);
//c3被s2选了
c3.getStudents().add(s2);
//如果双向关联,一定要一方放弃外键维护
session.save(s1);
session.save(s2);
/* session.save(c1);
session.save(c2);
session.save(c3);*/ transaction.commit();
session.close();
}
保存Course级联保存Student
<!-- 三.表示和课程的关系 -->
<!-- 3.1 set标签的name属性: 当前类中集合的名字 -->
<set name="students" table="s_c_table" cascade="save-update" inverse="true">
<!-- 3.2 key的column表示当前类在中间表的外键 -->
<key column="cid"/>
<!-- 3.3 many-to-many 表示多对对关系
column:表示另一方在中间表中的外键
class:表示另一方类的全限定名
-->
<many-to-many class="com.pri.bean.Student" column="sid"/>
</set>
/**
* 保存Course级联保存Student
* 在Course.hbm.xml里面配置:<set cascade="save-update">
*/
@Test
public void fun03(){
Session session = HibernateUtils.openSession();
Transaction transaction = session.beginTransaction(); Student s1 = new Student();
s1.setSname("张三");
Student s2 = new Student();
s2.setSname("李四"); Course c1 = new Course();
c1.setCname("C语言");
Course c2 = new Course();
c2.setCname("Java");
Course c3 = new Course();
c3.setCname("前端"); //s1选择了c1和c2
s1.getCourses().add(c1);
s1.getCourses().add(c2); //s2选择了c2 c3
s2.getCourses().add(c2);
s2.getCourses().add(c3); //c1被s1选了
c1.getStudents().add(s1);
//c2被s1,s2选了
c2.getStudents().add(s1);
c2.getStudents().add(s2);
//c3被s2选了
c3.getStudents().add(s2);
//如果双向关联,一定要一方放弃主键维护
/*session.save(s1);
session.save(s2);*/
session.save(c1);
session.save(c2);
session.save(c3); transaction.commit();
session.close();
}
注意的地方:
如果双向关联,一定要一方放弃主键维护
3.2级联删除【了解】
删除Student,级联删除Course 高数
/**
* 配置了级联删除 在Student.hbm.xml配置<set name="courses" table="s_c_tab" cascade="delete">
* 把id为1的学生删除,
* id为1的学生之前选过: id位1,2的课程.
* 级联删除既会删除正向多方数据库表中的记录,也会删除反向多方表中的记录和中间关系表中的记录
*/
@Test
public void fun02(){
Session session = HibernateUtils.openSession();
Transaction transaction = session.beginTransaction(); Student student = session.get(Student.class, 1);
session.delete(student); transaction.commit();
session.close();
}
注意的地方:
非级联删除只会删除正向多方数据库表和中间关系表中的记录,不会删除反向多方表中的记录
级联删除既会删除正向多方数据库表中的记录,也会删除反向多方表中的记录和中间关系表中的记录
开发过程中用的比较少
3.3其它操作
某个学生退课
/**
* 某个学生退课
* id为1的学生之前选过: id为1,2的课程.
* 现在的操作是:id为1的学生退掉ID为2的课程
*/
@Test
public void fun01(){
Session session = HibernateUtils.openSession();
Transaction transaction = session.beginTransaction();
//获得id为1的学生
Student s1 = session.get(Student.class, 1);
//获得id为2的课程
Course c2 = session.get(Course.class, 2); s1.getCourses().remove(c2);
transaction.commit();
session.close();
}
某个学生改课
/**
* 某个学生退课
* id为1的学生之前选过: id为1,2的课程.
* 现在的操作是:id为1的学生把id为2的课程改成id为3的课程
*/
@Test
public void fun02(){
Session session = HibernateUtils.openSession();
Transaction transaction = session.beginTransaction();
//获得id为1的学生
Student s1 = session.get(Student.class, 1);
//获得id为2的课程
Course c2 = session.get(Course.class, 2);
Course c3 = session.get(Course.class, 3); s1.getCourses().remove(c2);
s1.getCourses().add(c3);
transaction.commit();
session.close();
}
Hibernate入门(三)—— 一对多、多对多关系的更多相关文章
- JPA实体关系映射:@ManyToMany多对多关系、@OneToMany@ManyToOne一对多多对一关系和@OneToOne的深度实例解析
JPA实体关系映射:@ManyToMany多对多关系.@OneToMany@ManyToOne一对多多对一关系和@OneToOne的深度实例解析 今天程序中遇到的错误一 org.hibernate.A ...
- SSAS中事实表中的数据如果因为一对多或多对多关系复制了多份,在维度上聚合的时候还是只算一份
SSAS事实表中的数据,有时候会因为一对多或多对多关系发生复制变成多份,如下图所示: 图1 我们可以从上面图片中看到,在这个例子中,有三个事实表Fact_People_Money(此表用字段Money ...
- Hibernate 集合映射 一对多多对一 inverse属性 + cascade级联属性 多对多 一对一 关系映射
1 . 集合映射 需求:购物商城,用户有多个地址. // javabean设计 // javabean设计 public class User { private int userId; privat ...
- hibernate中一对多多对一关系设计的理解
1.单向多对一和双向多对一的区别? 只需要从一方获取另一方的数据时 就使用单向关联双方都需要获取对方数据时 就使用双向关系 部门--人员 使用人员时如果只需要获取对应部门信息(user.getdept ...
- SQLAlchemy_定义(一对一/一对多/多对多)关系
目录 Basic Relationship Patterns One To Many One To One Many To Many Basic Relationship Patterns 基本关系模 ...
- Hibernate框架学习(六)——一对多&多对一关系
一.关系表达 1.表中的表达 2.实体中的表达 3.orm元数据中的表达 一对多:(在Customer.hbm.xml中添加) 多对一:(在LinkMan.hbm.xml中添加) 最后别忘了在hibe ...
- hibernate 一对多 多对一 关系表 增删改查大礼包ps二级查也有
今天来到混元气功 这货大概的意思就是你中有我 我中有你 ps 这里就要说到维护关系 ps写这个用了我一下午.......也是刚刚好复习到这里 顺便就写写 注意:一般都在多方维护关系,至于是用单向还是用 ...
- Hibernate4.2.4入门(二)——一对多的映射关系
一.前言 前面我们已经学过hibernate的基础,学会增删改查简单的操作,然而我们数据库中存在着1对多,多对1,多对多的关系,hibernate又是基于ORM基础上的开源框架,可以让我们不用去编写S ...
- mybatis入门_一对多,多对多映射以及整合spring框架
一.一对多映射. 1.1 一对多映射之根据多的一方关联查询一的一方 示例:查询出具体的订单信息,同时也查询出来订单的用户信息. 引入的订单表如下所示: 框选出来的为具体的外键. 订单的Pojo类如下所 ...
- Hibernate入门(七)一对多入门案例
一对多 场景模拟:用户(一)对订单(多) 1.建表 创建客户表,字段有:客户id,客户姓名,客户性别,客户年龄,客户年纪,客户电话. 创建订单表,字段有:订单编号,明细编号,客户编号(外键) DROP ...
随机推荐
- lamp-linux-1
LAMP编程之Linux(1) LAMP:Linux Apache MySQL PHP LNMP:Linux Nginx MySQL PHP WAMP:Windows Apache MySQL PHP ...
- PHP中利用Redis管道加快执行
$redis->muti($mode)->get($key)->set($key)->exec(): 既然是这样的, 也就是说当我要使用管道执行一万次操作的时候需要写一万次操作 ...
- bash脚本编程学习笔记(二)
1.脚本编程之函数 函数是实现结构化编程重要的思想,主要目的是实现代码重用 定义一个函数: function FUNCNAME { command //函数体 } FUNCNAME(){ //函数 ...
- 官宣,PyTorch 1.0 稳定版本现已推出
简评:快来一起快乐地学习吧. 随着 PyTorch 生态系统和社区继续为开发人员提供有趣的新项目和教育资源,今天(12 月 7日)在 NeurIPS 会议上发布了 PyTorch 1.0 稳定版.研究 ...
- mac安装gdb调试(转载)
转载自:http://blog.plotcup.com/a/129 最近一直用go写一个项目,本想在mac上用gdb调试一下,但xcode4.6带的gdb版 本还是太低了,不支持go,只好自己安装一个 ...
- LINUX云服务器 安装 nginx
什么是nginx? 是一个高性能的 HTTP 和反向代理服务器,也是一个IMAP/POP3/SMTP 代理服, 是一个asynchronousservers异步服务器 为什么使用nginx? 因为它的 ...
- 使用GPIO监听中断
#include<stdlib.h> #include<stdio.h> #include<string.h> #include<unistd.h> # ...
- 2018焦作网络赛 - Poor God Water 一道水题的教训
本题算是签到题,但由于赛中花费了过多的时间去滴吧格,造成了不必要的浪费以及智商掉线,所以有必要记录一下坑点 题意:方格从1到n,每一格mjl可以选择吃鱼/巧克力/鸡腿,求走到n格时满足 1.每三格不可 ...
- html5: 复制到剪贴板 clipboard.js
1.使用clipboard.min.js工具,引用此js 注意事项: IOS微信网页开发中,若使用此工具来开发复制功能,则需要在超链接/按钮上新增 onclick=" " 2.cl ...
- pytest文档博客链接
关于pytest的博客: https://www.cnblogs.com/yoyoketang/tag/pytest/default.html?page=2