六、hibernate表与表之间的关系(多对多关系)
多对多关系
创建实体类和对应映射文件
Student.java
package com.qf.entity; import java.util.HashSet;
import java.util.Set; public class Student { private Long sid;
private String sname;
//一个学生可以有很多个老师
private Set<Teacher> teachs = new HashSet<>(); public Long getSid() {
return sid;
}
public void setSid(Long sid) {
this.sid = sid;
} public String getSname() {
return sname;
}
public void setSname(String sname) {
this.sname = sname;
} public Set<Teacher> getTeachs() {
return teachs;
}
public void setTeachs(Set<Teacher> teachs) {
this.teachs = teachs;
}
@Override
public String toString() {
return "Student [sid=" + sid + ", sname=" + sname + ", teachs=" + teachs + "]";
} }
Student.hbm.xml
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE hibernate-mapping PUBLIC
"-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd">
<hibernate-mapping>
<!-- 配置表与实体的映射关系 -->
<class name="com.qf.entity.Student" table="student">
<id name="sid" column="sid">
<generator class="native"></generator>
</id>
<property name="sname" column="sname"/>
<set name="teachs" table="teach_stu" >
<key column="sid"/>
<many-to-many class="com.qf.entity.Teacher" column="tid" />
</set>
</class>
</hibernate-mapping>
Teacher.java
package com.qf.entity; import java.util.HashSet;
import java.util.Set; public class Teacher {
private long tid;
private String tname;
private String course;
//一个教师可以有多个学生
private Set<Student> stus = new HashSet<Student>(); public Set<Student> getStus() {
return stus;
}
public void setStus(Set<Student> stus) {
this.stus = stus;
}
public long getTid() {
return tid;
}
public void setTid(long tid) {
this.tid = tid;
}
public String getTname() {
return tname;
}
public void setTname(String tname) {
this.tname = tname;
}
public String getCourse() {
return course;
}
public void setCourse(String course) {
this.course = course;
}
@Override
public String toString() {
return "Teacher [tid=" + tid + ", tname=" + tname + ", course=" + course + "]";
} }
Teacher.hbm.xml
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE hibernate-mapping PUBLIC
"-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd">
<hibernate-mapping>
<!-- 配置表与实体的映射关系 -->
<class name="com.qf.entity.Teacher" table="teacher">
<id name="tid" column="tid">
<generator class="native"/>
</id>
<property name="tname" column="tname"/>
<property name="course" column="course"/>
<set name="stus" table="teach_stu">
<key column="tid"></key>
<many-to-many class="com.qf.entity.Student" column="sid"/>
</set>
</class>
</hibernate-mapping>
测试
@Test
public void test() {
Session session = SessionFactoryUtil.getSession();
Transaction tx = session.beginTransaction(); //创建两个教师对象,三个学生对象
//学生选择老师
Teacher t1 = new Teacher();
t1.setTname("张老师");
Teacher t2 = new Teacher();
t2.setTname("李老师");
Student s1 = new Student();
s1.setSname("张三");
Student s2 = new Student();
s2.setSname("李四");
Student s3 = new Student();
s3.setSname("王五"); //学生和老师之间建立双向关系
//多对多关系建立双向关系后,双方必须有一方放弃维护外键关系权(inverse),否则会因为中间表主键重复抛出异常
s1.getTeachs().add(t1);
s1.getTeachs().add(t2);
s3.getTeachs().add(t1);
s2.getTeachs().add(t2);
t1.getStus().add(s1);
t1.getStus().add(s3);
t2.getStus().add(s2);
t2.getStus().add(s1); session.save(s1);
session.save(s2);
session.save(s3);
session.save(t1);
session.save(t2); tx.commit();
}
-------------------------------------console-------------------------------------
Hibernate: alter table teach_stu drop foreign key FKsrw3nh8oe5xhmqqxm2qng952t
Hibernate: alter table teach_stu drop foreign key FKtc48sy6cweqkufd4c777i8vsp
Hibernate: drop table if exists student
Hibernate: drop table if exists teach_stu
Hibernate: drop table if exists teacher
Hibernate: create table student (sid bigint not null auto_increment, sname varchar(255), primary key (sid))
Hibernate: create table teach_stu (tid bigint not null, sid bigint not null, primary key (sid, tid))
Hibernate: create table teacher (tid bigint not null auto_increment, tname varchar(255), course varchar(255), primary key (tid))
Hibernate: alter table teach_stu add constraint FKsrw3nh8oe5xhmqqxm2qng952t foreign key (sid) references student (sid)
Hibernate: alter table teach_stu add constraint FKtc48sy6cweqkufd4c777i8vsp foreign key (tid) references teacher (tid)
11:21:37,135 INFO SchemaExport:464 - HHH000230: Schema export complete
Hibernate: insert into student (sname) values (?)
Hibernate: insert into student (sname) values (?)
Hibernate: insert into student (sname) values (?)
Hibernate: insert into teacher (tname, course) values (?, ?)
Hibernate: insert into teacher (tname, course) values (?, ?)
Hibernate: insert into teach_stu (sid, tid) values (?, ?)
Hibernate: insert into teach_stu (sid, tid) values (?, ?)
Hibernate: insert into teach_stu (sid, tid) values (?, ?)
Hibernate: insert into teach_stu (sid, tid) values (?, ?)
Hibernate: insert into teach_stu (tid, sid) values (?, ?)
11:21:37,270 WARN SqlExceptionHelper:127 - SQL Error: 1062, SQLState: 23000
11:21:37,271 ERROR SqlExceptionHelper:129 - Duplicate entry '1-1' for key 'PRIMARY'
11:21:37,271 INFO AbstractBatchImpl:193 - HHH000010: On release of batch it still contained JDBC statements
11:21:37,272 ERROR SessionImpl:2994 - HHH000346: Error during managed flush [could not execute statement]
原因
测试中因为建立了双向关系,所以teacher和student都会去维护外键,导致相同的(1,1)会两次插入中间关系表teach_stu中
解决办法
一方放弃维护外键关系权。一般被动主体放弃维护外键权,比如学生选择老师,老师放弃维护外键权;老师选择学生,学生放弃维护外键权
修改Teacher.hbm.xml:<set name="stus" table="teach_stu" inverse="true">
-------------------------------------console-------------------------------------
Hibernate: alter table teach_stu drop foreign key FKsrw3nh8oe5xhmqqxm2qng952t
Hibernate: alter table teach_stu drop foreign key FKtc48sy6cweqkufd4c777i8vsp
Hibernate: drop table if exists student
Hibernate: drop table if exists teach_stu
Hibernate: drop table if exists teacher
Hibernate: create table student (sid bigint not null auto_increment, sname varchar(255), primary key (sid))
Hibernate: create table teach_stu (tid bigint not null, sid bigint not null, primary key (sid, tid))
Hibernate: create table teacher (tid bigint not null auto_increment, tname varchar(255), course varchar(255), primary key (tid))
Hibernate: alter table teach_stu add constraint FKsrw3nh8oe5xhmqqxm2qng952t foreign key (sid) references student (sid)
Hibernate: alter table teach_stu add constraint FKtc48sy6cweqkufd4c777i8vsp foreign key (tid) references teacher (tid)
11:30:43,077 INFO SchemaExport:464 - HHH000230: Schema export complete
Hibernate: insert into student (sname) values (?)
Hibernate: insert into student (sname) values (?)
Hibernate: insert into student (sname) values (?)
Hibernate: insert into teacher (tname, course) values (?, ?)
Hibernate: insert into teacher (tname, course) values (?, ?)
Hibernate: insert into teach_stu (sid, tid) values (?, ?)
Hibernate: insert into teach_stu (sid, tid) values (?, ?)
Hibernate: insert into teach_stu (sid, tid) values (?, ?)
Hibernate: insert into teach_stu (sid, tid) values (?, ?)
数据成功插入数据库
级联保存
保存学生级联保存教师
主体是学生,所以修改学生的映射文件Student.hbm.xml
<hibernate-mapping>
<!-- 配置表与实体的映射关系 -->
<class name="com.qf.entity.Student" table="student">
<id name="sid" column="sid">
<generator class="native"></generator>
</id>
<property name="sname" column="sname"/>
<set name="teachs" table="teach_stu" cascade="save-update" >
<key column="sid"/>
<many-to-many class="com.qf.entity.Teacher" column="tid" />
</set>
</class>
</hibernate-mapping>
测试方法
@Test
public void test() {
Session session = SessionFactoryUtil.getSession();
Transaction tx = session.beginTransaction(); //保存学生级联保存教师
Teacher t1 = new Teacher();
t1.setTname("张老师");
Student s1 = new Student();
s1.setSname("张三"); t1.getStus().add(s1);
s1.getTeachs().add(t1); session.save(s1); tx.commit();
}
-------------------------------------console-------------------------------------
Hibernate: create table student (sid bigint not null auto_increment, sname varchar(255), primary key (sid))
Hibernate: create table teach_stu (tid bigint not null, sid bigint not null, primary key (sid, tid))
Hibernate: create table teacher (tid bigint not null auto_increment, tname varchar(255), course varchar(255), primary key (tid))
Hibernate: alter table teach_stu add constraint FKsrw3nh8oe5xhmqqxm2qng952t foreign key (sid) references student (sid)
Hibernate: alter table teach_stu add constraint FKtc48sy6cweqkufd4c777i8vsp foreign key (tid) references teacher (tid)
14:22:37,418 INFO SchemaExport:464 - HHH000230: Schema export complete
Hibernate: insert into student (sname) values (?)
Hibernate: insert into teacher (tname, course) values (?, ?)
Hibernate: insert into teach_stu (sid, tid) values (?, ?
级联删除(一般不使用)
想以哪一方为主体删除另一方,就在哪一方映射文件中配置cascade属性:
<set name="teachs" table="teach_stu" cascade="delete" >
六、hibernate表与表之间的关系(多对多关系)的更多相关文章
- 【Java EE 学习 46】【Hibernate学习第三天】【多对多关系映射】
一.多对多关系概述 以学生和课程之间的关系为例. 1.在多对多关系中涉及到的表有三张,两张实体表,一张专门用于维护关系的表. 2.多对多关系中两个实体类中应当分别添加对方的Set集合的属性,并提供se ...
- day 7-15 表与表之间的关系
一. 前言 表与 表之间有3种对应关系,分别是: 多对一:一张表中的一个字段中的多个值对应另外一张表中的一个字段值.(多个学生,可以学习同一门课程) 多对多;一张表中的一个字段值对应另外一张表中的多个 ...
- day 69 orm操作之表关系,多对多,多对一(wusir总结官网的API)
对象 关系 模型 wusir博客地址orm官网API总结 django官网orm-API orm概要: ORM 跨表查询 class Book(models.Model): title = mod ...
- EF Core中如何设置数据库表自己与自己的多对多关系
本文的代码基于.NET Core 3.0和EF Core 3.0 有时候在数据库设计中,一个表自己会和自己是多对多关系. 在SQL Server数据库中,现在我们有Person表,代表一个人,建表语句 ...
- Django中多对多关系的orm表设计
作者的管理 1.设计表结构 出版社 书籍 作者 一个出版社出版多个书籍 1对多 书籍和作者的关系:一个作者写多本书,一本书可以是多个作者写.多对多 1)创建一张表,表中多对多的数据关系.使用 多对多 ...
- [MySQL数据库之表的约束条件:primary key、auto_increment、not null与default、unique、foreign key:表与表之间建立关联]
[MySQL数据库之表的约束条件:primary key.auto_increment.not null与default.unique.foreign key:表与表之间建立关联] 表的约束条件 约束 ...
- django ORM模型表的一对多、多对多关系、万能双下划线查询
一.外键使用 在 MySQL 中,如果使用InnoDB引擎,则支持外键约束.(另一种常用的MyIsam引擎不支持外键) 定义外键的语法为fieldname=models.ForeignKey(to_c ...
- 【Hibernate】多对多关系的表达
User.hbm.xml <?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE hibernate ...
- 07 Mybatis的多表查询1----1对多和多对1---@Results注解用法总结
1.表与表之间的关系及其举例 表之间的关系有4种:一对多.多对一.一对一.多对多. 举例: (1)用户和订单就是一对多 一个用户可以下多个订单 (2)订单和用户就是多对一 多个订单属于同一个用户 (3 ...
随机推荐
- 利用delegate来解决类之间相互引用问题(引用死锁)
类之间相互引用--类A中需要调用类B中的方法,同时,类B中又要调用类A中的方法.(也被称为引用死锁,通常会出现编译错误). 解决方法是,在类A中引用类B,并使类A成为类B的delegate,这样在类A ...
- 大哥带我走渗透8--CSRF的应用
1.大哥给了一个CSRF实战视频,真的很简单,但是我今天晚上有点不在状态,很多简单的问题也没有想.所以做了一个多小时.这件事给我的启发就是,无论发生什么事,都不要影响自己的学习.先写点废话,真的真的, ...
- C语言字符串复制
strcpy(arg1,arg2);//将arg2内容赋值到arg1 strncpy(arg1,arg2,size);//赋值多少由size决定,如果要截取某一部分,可以将arg2指针进行arg2+x ...
- 98-基于FPGA Spartan6 的双路光纤PCIe采集卡(2路光纤卡) 光纤PCIe卡
1.板卡概述 板卡采用xilinx Spartan6系列芯片,支持 PCI Express Base Specification 1.1 x1.内含丰富的逻辑资源和存储单元,板卡FPGA外接双片32M ...
- MySQL优化系列之一
MySQL数据库常见的两个瓶颈是CPU和I/O. CPU在饱和的情况下一般发生在数据装入内存或者从磁盘上读取数据的时候,当装入的数据远大于 内存容量的时候,这时可能会发生I/O瓶颈, 如果是分布式应用 ...
- [Luogu1938][USACO09NOV]找工就业Job Hunt
原题链接:https://www.luogu.org/problem/show?pid=1938 这一道题有一个比较难的点就是,这一张图上,是点上有权.既然点上有权的话,我们就不好一下子使用最短路了. ...
- 3.自定义返回json格式的数据给前台(自定义Controller类中的Json方法)
在mvc的项目中,我们前台做一些操作时,后台要返回一些结果给前台,这个时候我们就需要有一个状态来标识到底是什么类型的错误, 例如: 执行删除的时候,如果操作成功(1行受影响),我们需要返回状态为1并输 ...
- BestCoder Round #92 (hdu 6015 6016)
比赛链接 A题主要是map的使用,比赛的时候问了下队友,下次要记住了 #include<bits/stdc++.h> using namespace std; typedef long l ...
- RabbitMQ之交换机
1. 交换机类型 rabbitmq常见有四种交换机类型: direct, topic, fanout, headers. 一般headers都不用,工作中用得较多的是fanout,它会将消息推送到所有 ...
- JS中数据结构之散列表
散列是一种常用的数据存储技术,散列后的数据可以快速地插入或取用.散列使用的数据 结构叫做散列表.在散列表上插入.删除和取用数据都非常快. 下面的散列表是基于数组进行设计的,数组的长度是预先设定的,如有 ...