Hibernate多表关系配置
1.表的关系
2.一对多配置
3.级联操作
4.多对多配置
5.多对多操作
1
表的关系
表之间的关系
一对多(一个部门有多个员工,一个员工只能属于某一个部门)
多对多(一个老师教多个学生,一个学生可以被多个老师教)
一对一(一个公司只能对应一个注册地址)
表之间关系建表原则
一对多(在多的一方创建一个外键,指向一的一方的主键)
多对多(创建一个中间表,中间表至少有两个字段,分别作为外键指向多对多双方的主键)
一对一(唯一外键对应或主键对应)
2
一对多配置
1.建表(班级、学生)
class_id | class_name | numbers |
---|
stu_id | stu_name | stu_age | class_id |
---|
2.建立ORM
domain类
@Getter@Setter
public class Classes {
private Integer class_id;
private String class_name;
private Integer class_student;
//一个班级包含多个学生
private Set<Student> students = new HashSet<>();
}
@Setter@Getter
public class Student {
private Integer stu_id;
private String stu_name;
private Integer stu_age;
//一个学生属于一个班级
private Classes stu_class;
}
映射文件
映射文件中普通字段段的配置不用写上外键,在一的一方配置文件写上set标签name属性为关联属性名,里面还有key标签有column属性关系中的外键即另一个表的外键字段名,还有一个标签one-to-many写上另一表的domain类全路径。在多的一方只有一个many-to-one标签里面name属性也是关联属性名,class属性关系表它的domain地址,还有一个column外键
<hibernate-mapping>
<class name="com.hao.domain.Classes" table="classes">
<id name="class_id" >
<generator class="identity"/>
</id>
<property name="class_name"/>
<set name="students">
<key column="class_id"></key>
<one-to-many class="com.hao.domain.Student"></one-to-many>
</set>
</class>
</hibernate-mapping>
<hibernate-mapping>
<class name="com.hao.domain.Student" table="student">
<id name="stu_id">
<generator class="identity"/>
</id>
<property name="stu_name" />
<property name="stu_age" />
<many-to-one name="stu_class" class="com.hao.domain.Classes" column="class_id" lazy="false"></many-to-one>
</class>
</hibernate-mapping>
3.添加核心配置文件
<mapping resource="com/hao/domain/Student.hbm.xml"/>
<mapping resource="com/hao/domain/Classes.hbm.xml"/>
4.编写测试类
public void saveTest() {
Session session = HibernateUtil.openSession();
Transaction tra = session.beginTransaction();
//创建三个班级
Classes c1 = new Classes();
Classes c2 = new Classes();
Classes c3 = new Classes();
c1.setClass_name("c1");
c2.setClass_name("c2");
c3.setClass_name("c3");
//创建三个学生
Student s1 = new Student();
Student s2 = new Student();
Student s3 = new Student();
s1.setStu_name("张三");
s2.setStu_name("李四");
s3.setStu_name("王五");
//班级1添加两个学生,班级2添加一个学生
c1.getStudents().add(s1);
c1.getStudents().add(s2);
c2.getStudents().add(s3);
//保存全部
session.save(s1);
session.save(s2);
session.save(s3);
session.save(c1);
session.save(c2);
session.save(c3);
tra.commit();
}
结果
class_id | class-name | numbers |
---|---|---|
1 | c1 | null |
2 | c2 | null |
3 | c3 | null |
stu_id | stu_name | stu_age | class_id |
---|---|---|---|
1 | s1 | null | 1 |
2 | s2 | null | 1 |
3 | s3 | null | 2 |
默认是先保存各自的内容,再建立连接(添上外键),删除也是先去掉外键再删除。接下来通过级联操作实现关联关系表同步更新
3
级联操作
按照上面的操作保存3个班级3个学生,共六条保存
理论上只保存一边是可行的。
比如只保存班级c1、c2、c3,它们添加了s1、s2、s3。
所以添加班级也会在学生表中添加对应的记录。
但是实际上会报错——瞬时对象异常
这是因为保存的对象关联了处于瞬时态的对象
我们可以在配置文件中去开启级联操作
在哪个配置文件去开启,就在它对应的domain保存时才有级联
在Classes的映射文件去添加cascade,保存classes时就会级联保存不用再单独去保存student,关联信息本来在classes就有
<set name="students" cascade="save-update">
<key column="class_id" ></key>
<one-to-many class="com.hao.domain.Student" ></one-to-many>
</set>
还可以写在Student的映射文件,这样保存student就会同时保存关联的classes信息
<many-to-one cascade="save-update" name="stu_class" class="com.hao.domain.Classes" column="class_id" lazy="false" ></many-to-one>
在更新时也会有级联操作,当classes移除一个学生,那么student表会变
还有删除,当删除一个班级,那么student表中属于这个班的student也会全删掉
cascade="delete"
4
多对多配置
配置和一对多一样,只是set标签中多一个table属性值为中间关系表的表名
建表
course_id | course_name |
---|
stu_id | stu_name | stu_age | class_id |
---|
stu_id | course_id |
---|
建立ORM
domain类
@Setter@Getter
public class Student {
private Integer stu_id;
private String stu_name;
private Integer stu_age;
//一个学生有多门课程
private set<Course> courses;
}
@Setter@Getter
public class Course {
private Integer Course_id;
private String Course_name;
//一个课程有众多学生学习
private set<Student> students;
}
映射文件
<set name="courses" table="c-s" cascade="save-update,delete">
<key column="stu_id"></key>
<many-to-many class="com.hao.domain.Course" column="course_id"></many-to-many>
</set>
<set name="students" table="c-s">
<key column="course_id"></key>
<many-to-many class="com.hao.domain.Student" column="stu_id"></many-to-many>
</set>
最后再在核心配置文件加载上映射文件
<mapping resource="com/hao/domain/Course.hbm.xml"/>
编写测试
@Test
public void manytomany(){
Course c1 = new Course();
Course c2 = new Course();
Course c3 = new Course();
c1.setCourse_name("语文");
c2.setCourse_name("数学");
c3.setCourse_name("英语");
Student s1 = new Student();
Student s2= new Student();
Student s3 = new Student();
s1.setStu_name("张三");
s2.setStu_name("李四");
s3.setStu_name("王五");
c1.getStudents().add(s1);
c1.getStudents().add(s2);
c1.getStudents().add(s3);
c2.getStudents().add(s1);
c3.getStudents().add(s2);
c3.getStudents().add(s3);
Session session = HibernateUtil.openSession();
Transaction tra = session.beginTransaction();
session.save(c1);
session.save(c2);
session.save(c3);
tra.commit();
}
5
多对多操作
对多对的操作双方的关系都在中间表上,都在各自得关联集合中。所以它们得操作就是操作集合
给上面王五添加数学课
@Test
public void manytomany(){
Session session = HibernateUtil.openSession();
Transaction tra = session.beginTransaction();
//获取王五
Student stu = session.get(Student.class,1);
//获取数学课
Course course = session.get(Course.class,2)
//修改集合
stu.getCourses().add(course);
tra.commit();
}
其他也是一样
给王五删除数学课
@Test
public void manytomany(){
Session session = HibernateUtil.openSession();
Transaction tra = session.beginTransaction();
//获取王五
Student stu = session.get(Student.class,1);
//获取数学课
Course course = session.get(Course.class,2)
//修改集合
stu.getCourses().remove(course);
tra.commit();
}
给王五把英语课改为数学课(其实就是前面的删除和添加)
@Test
public void manytomany(){
Session session = HibernateUtil.openSession();
Transaction tra = session.beginTransaction();
//获取王五
Student stu = session.get(Student.class,1);
//获取英语课
Course course1 = session.get(Course.class,3);
//获取数学课
Course course2 = session.get(Course.class,2);
//修改集合
stu.getCourses().remove(course1);
stu.getCourses().add(course2);
tra.commit();
}
特别注意:事务提交、建表引擎(坑)