多对多关系
创建实体类和对应映射文件
Student.java
1 package com.qf.entity; 2 3 import java.util.HashSet; 4 import java.util.Set; 5 6 public class Student { 7 8 private Long sid; 9 private String sname; 10 //一个学生可以有很多个老师 11 private Set<Teacher> teachs = new HashSet<>(); 12 13 public Long getSid() { 14 return sid; 15 } 16 public void setSid(Long sid) { 17 this.sid = sid; 18 } 19 20 public String getSname() { 21 return sname; 22 } 23 public void setSname(String sname) { 24 this.sname = sname; 25 } 26 27 public Set<Teacher> getTeachs() { 28 return teachs; 29 } 30 public void setTeachs(Set<Teacher> teachs) { 31 this.teachs = teachs; 32 } 33 @Override 34 public String toString() { 35 return "Student [sid=" + sid + ", sname=" + sname + ", teachs=" + teachs + "]"; 36 } 37 38 }
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
1 package com.qf.entity; 2 3 import java.util.HashSet; 4 import java.util.Set; 5 6 public class Teacher { 7 private long tid; 8 private String tname; 9 private String course; 10 //一个教师可以有多个学生 11 private Set<Student> stus = new HashSet<Student>(); 12 13 public Set<Student> getStus() { 14 return stus; 15 } 16 public void setStus(Set<Student> stus) { 17 this.stus = stus; 18 } 19 public long getTid() { 20 return tid; 21 } 22 public void setTid(long tid) { 23 this.tid = tid; 24 } 25 public String getTname() { 26 return tname; 27 } 28 public void setTname(String tname) { 29 this.tname = tname; 30 } 31 public String getCourse() { 32 return course; 33 } 34 public void setCourse(String course) { 35 this.course = course; 36 } 37 @Override 38 public String toString() { 39 return "Teacher [tid=" + tid + ", tname=" + tname + ", course=" + course + "]"; 40 } 41 42 43 }
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" >