一个人可以买多种商品,一种商品可以被多个人所购买。
一个学生可以选多门课程,一个课程可以被多个学生选择。
一个老师可以带多个班级,一个班级可以被多个老师带。这些都是多对多的关系。
以老师和班级为例。要建立两者之间的关系需要三张表。一张老师表,一张班级表,还需要一张用来维护关系的中间表。
知道三张表之间的关系后就可以着手写代码了。
1、先建实体类。建一个教师的实体类和一个班级的实体类。给定各自所有的属性,并在教师实体类中给定一个set集合用来存放班级信息。在班级实体类中给定一个set集合用来存放教师信息。并给定set、get方法。
package cn.otote.entity;
import java.util.Set;
public class Teacher {
private Integer id;
private String name;
//用于存放班级信息的set
private Set<Classes> classesSet;
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;
}
public Set<Classes> getClassesSet() {
return classesSet;
}
public void setClassesSet(Set<Classes> classesSet) {
this.classesSet = classesSet;
}
}
package cn.otote.e
ntity;
import java.util.Set;
public class Classes {
private Integer id;
//班级名称
private String className;
//用于存放教师信息的set
private Set<Teacher> teacherSet;
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getClassName() {
return className;
}
public void setClassName(String className) {
this.className = className;
}
public Set<Teacher> getTeacherSet() {
return teacherSet;
}
public void setTeacherSet(Set<Teacher> teacherSet) {
this.teacherSet = teacherSet;
}
}
2、配置Teacher的映射文件。
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN" "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<!-- package为实体类所在的包名 -->
<hibernate-mapping package="cn.otote.entity">
<class name="Teacher" table="t_teacher" >
<id name="id" column="id">
<!-- class="native"将主键id设为自增 -->
<generator class="native"/>
</id>
<property name="name" ></property>
<!-- name为存放另一方的set名称 table为中间表的表名 -->
<set name="classesSet" table="t_teacher_classes">
<!-- key为当前表在中间表的外键 当前表是t_teacher 所以中间表的外键是t_id -->
<key column="t_id"></key>
<!-- 配置多对多 class为另一方的类型 column为另一方在中间表的外键 另一方为班级classes所以外键为c_id -->
<many-to-many class="Classes" column="c_id"></many-to-many>
</set>
</class>
</hibernate-mapping>
3、配置Classes的映射文件,两者恰好相反。
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN" "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<!-- package为实体类所在的包名 -->
<hibernate-mapping package="cn.otote.entity">
<class name="Classes" table="t_classes" >
<id name="id" column="id">
<!-- class="native"将主键id设为自增 -->
<generator class="native"/>
</id>
<property name="className" column="class_name" ></property>
<!-- name为存放另一方的set名称 table为中间表的表名 -->
<set name="teacherSet" table="t_teacher_classes">
<!-- key为当前表在中间表的外键 当前表是t_classes 所以中间表的外键是c_id -->
<key column="c_id"></key>
<!-- 配置多对多 class为另一方的类型 column为另一方在中间表的外键 另一方为班级teacher所以外键为t_id -->
<many-to-many class="Teacher" column="t_id"></many-to-many>
</set>
</class>
</hibernate-mapping>
4、在hibernate.cfg.xml将两个映射文件加进去。
5、测试
@Test
void test() {
Session session = HibernateUtil.getSessionFactory().getCurrentSession();
Transaction transaction = session.beginTransaction();
//创建两个班级
Classes classes1=new Classes();
classes1.setClassName("初一一班");
Classes classes2=new Classes();
classes2.setClassName("初一三班");
//创建两个老师
Teacher teacher1=new Teacher();
teacher1.setName("张老师");
Teacher teacher2=new Teacher();
teacher2.setName("李老师");
//默认是双方都维护关系 但是只要一方维护关系就可以了 这里通过教师这一方来维护关系
teacher1.setClassesSet(new HashSet<>());
Set<Classes> classesSet1 = teacher1.getClassesSet();
//将两个班级都放到第一个老师的set集合中
classesSet1.add(classes1);
classesSet1.add(classes2);
teacher2.setClassesSet(new HashSet<>());
Set<Classes> classesSet2 = teacher2.getClassesSet();
//将两个班级都放到第二个老师的set集合中
classesSet2.add(classes1);
classesSet2.add(classes2);
//保存数据
session.save(classes1);
session.save(classes2);
session.save(teacher1);
session.save(teacher2);
//提交事务
transaction.commit();
}
运行完打开数据库可以发现三张表都已经建立好了,中间表的外键也都设置好了。再看数据,教师表和班级表的数据都已经插入,中间表的数据也维护好了。
中间表的外键:
教师表:
班级表:
中间表数据:
需要注意的是多对多默认是双方都维护关系的,所以我们只需要维护一方的关系就行了,如果操作时双方都维护的话会报错。当然也可以通过设置反转来让一方维护。