【SSH】SSH之Hibernate框架:在hibernate中的配置表关系和执行级联操作

一、数据库中表之间的关系以及如何创建:

数据库中表的关系有以下三种:
1、一对多(也即多对一):在“多”的一方设置与“一”的一方的主键关联的外键;
2、多对多:创建一个至少有两个字段的中间表,其中两个字段分别设置成与关系表的主键关联的外键。多对多关系可以看作是两个一对多关系:“一”的一方是关系表,“多”的一方是中间表;
3、一对一:创建一对“一对多”关系的表,把“多”的一方的外键设置为unique;或者将两个表的主键设置为相等的将其关联起来;或者干脆就合并为一张表更为省事。

二、一对多关系的表在hibernate中的配置:

1、如何在数据库中创建“一对多”关系的表
在“多”的一方设置与“一”的一方的主键关联的外键

##一的一方:部门表
CREATE TABLE `com_department` (
	`dep_id` bigint(20) NOT NULL AUTO_INCREMENT,
	`dep_name` varchar(255) DEFAULT NULL,
	`dep_manager` varchar(255) DEFAULT NULL,
	PRIMARY KEY (`dep_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

##多的一方:员工表,设置外键关联部门表的主键
CREATE TABLE `com_employee` (
	`emp_id` bigint(20) NOT NULL AUTO_INCREMENT,
	`emp_dep_id` bigint(20) DEFAULT NULL,
	`emp_age` int(3) DEFAULT NULL,
	`emp_gender` varchar(3) DEFAULT NULL,
	`emp_name` varchar(255) DEFAULT NULL,  
	PRIMARY KEY (`emp_id`),
	constraint employee_department_id_fk foreign key(emp_dep_id) references com_department(dep_id)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

2、如何在实体类中表明对应数据库中的表的“一对多”关系
在“一”的一方声明一个Set集合类型的成员变量,存放“多”的一方的对象:

package cn.company.vo;

import java.util.HashSet;
import java.util.Set;

public class Department {
	
	private Long id;
	private String name;
	private String manager;
	//声明一个Set集合类型的成员变量,存放“多”的一方的对象
	private Set<Employee> employee = new HashSet<Employee>();
	
	//...节省篇幅,此处省略get/set方法
	
	@Override
	public String toString() {
		return "Department [id=" + id + ", name=" + name + ", manager=" + manager + "]";
	}
}

在“多”的一方声明一个“一”的一方对应的类类型,保存“一”的一方的对象:

package cn.company.vo;

public class Employee {
	
	private Long id;
	private Integer age;
	private String gender;
	private String name;
	//声明一个“一”的一方对应的类类型,保存“一”的一方的对象
	private Department department;

	//...节省篇幅,此处省略get/set方法
	
	@Override
	public String toString() {
		return "Employee [id=" + id + ", age=" + age + ", gender=" + gender + ", name=" + name + "]";
	}
}

3、如何在映射文件中表明对应数据库中的表的“一对多”关系
在“一”的一方设置set标签:

  • set标签属性name表示当前类中声明的多的一方的Set集合的成员属性名称;
  • set标签的子标签key的column属性表示外键名称;
  • set标签的子标签one-to-many的class属性表示“多”的一方对应类的全路径。
<?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="cn.company.vo.Department" table="com_department">
		<id name="id" column="dep_id">
			<generator class="native"/>
		</id>
		<property name="name" column="dep_name"/>
		<property name="manager" column="dep_manager"/>
		<!-- 在“一”的一方设置set标签 -->
		<set name="employee">
			<key column="emp_dep_id"/>
			<one-to-many class="cn.company.vo.Employee"/>
		</set>
	</class>
</hibernate-mapping>

在“一”的一方配置many-to-one标签:

  • many-to-one标签的属性name表示当前类中声明的“一”的一方对应类的属性名称;
  • many-to-one标签的属性column表示外键名称;
  • many-to-one标签的属性class表示“一”的一方对应类的全路径。
<?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="cn.company.vo.Employee" table="com_employee">
		<id name="id" column="emp_id">
			<generator class="native"/>
		</id>
		<property name="age" column="com_age"/>
		<property name="gender" column="com_gender"/>
		<property name="name" column="com_name"/>
		<!-- 在“一”的一方配置many-to-one标签 -->
		<many-to-one name="department" column="emp_dep_id" class="cn.company.vo.Department"/>
	</class>
</hibernate-mapping>

4、测试
下面编写个测试类:
在这里插入图片描述
此时部门表和员工表如下:
在这里插入图片描述
在这里插入图片描述

三、级联删除、保存或更新

从上面的测试类可以发现保存部门和员工的时候,每个对象都要单独做一次保存,这样是非常麻烦的,那么有没有更加简便的方法呢?当然是有的,可以用级联保存或更新

1、级联保存或更新:

即在保存有关联关系的持久类对象的一方时,自动保存另外一方。这样做的前提是在保存的一方的映射文件中进行配置:

  • 如果保存的一的一方级联保存多的一方,则在一的一方的映射文件中为set标签的cascade属性赋值为“save-update”;
  • 如果保存的多的一方级联保存一的一方,则在多的一方的映射文件中为many-to-one标签的cascade属性赋值为“save-update”;

例如
a.为上面的Department.hbm.xml文件中的set标签配置cascade属性

<!-- 在“一”的一方设置set标签 -->
<set name="employee" cascade="save-update">
	<key column="emp_dep_id"/>
	<one-to-many class="cn.company.vo.Employee"/>
</set>

则上面测试类中的保存操作可以进行简化:
在这里插入图片描述
b.为上面的Employee.hbm.xml文件中的many-to-one标签配置cascade属性

<!-- 在“一”的一方配置many-to-one标签 -->
<many-to-one  cascade="save-update" name="department" column="emp_dep_id" class="cn.company.vo.Department"/>

则上面测试类中的保存操作可以进行简化:
在这里插入图片描述

2、级联删除:

从上面的级联保存或更新我们可以推断出级联删除的作用,即删除一方时,被关联的另外一方也会被删除。其配置也与级联保存或更新一样,只不过cascade的属性值要改为“delete”或者改为“save-update,delete”。
注意:级联删除在一对多关系中通常用在一的一方,这也很好理解。拿上面部门和员工的关系来说,删除部门级联删除部门里的员工是符合逻辑的,但是某个员工离职或者转移出该部门了,总不能把该部门也级联删除了吧?

四、inverse:是否放弃对外键的维护

在进行涉及到两个表关系的修改操作时,如果没有考虑inverse属性的配置,那么程序将对表的外键进行两次修改,例如下面的操作:
在这里插入图片描述
当执行之后我们可以发现,程序发送了两次修改外键的SQL语句:
在这里插入图片描述
第二次的修改其实是多余的,有人也许对此不以为意,认为这都是细枝末节不用理会。这种观点是错误的,要知道频繁的对操作数据库是很消耗性能的,而且多余的操作是耗时的。为了避免这个问题,我们需要配置inverse属性。
inverse属性:该属性在于使有外键关联的两个表之一放弃对外键的维护权,这样的话在进行涉及到两个表关系的操作时就只会修改一次外键。该属性的使用位置与cascade一样,true表示放弃,false表示不放弃。例:

<!-- 在“一”的一方设置set标签 -->
<set name="employee" cascade="save-update" inverse="true">
	<key column="emp_dep_id"/>
	<one-to-many class="cn.company.vo.Employee"/>
</set>

此时就没有多余的SQL语句了。
注意

  • a.该属性一般用在一的一方,原因很好理解,让全国14亿人记住国家主席的姓名是很简单的,但是让国家主席记住14亿人的姓名是不可能的;
  • b.该属性用在保存操作中时需要小心,如果一的一方即设置了级联保存又设置了放弃维护外键,执行操作之后外键将为null,因为此时外键仅由一的一方维护而一的一方却将之放弃了。

五、多对多关系的表在hibernate中的配置:

1、如何在数据库中创建“一对多”关系的表
创建一个至少有两个字段的中间表,其中两个字段分别设置成与关系表的主键关联的外键。多对多关系可以看作是两个一对多关系:“一”的一方是关系表,“多”的一方是中间表。

##多的一方:课程表
CREATE TABLE sch_course (
  cou_id bigint(20) NOT NULL AUTO_INCREMENT,
  cou_name varchar(255) DEFAULT NULL,
  role_credit int(3) DEFAULT NULL,
  PRIMARY KEY (cou_id)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
##多的一方:学生表
CREATE TABLE sch_student (
  stu_id bigint(20) NOT NULL AUTO_INCREMENT,
  stu_name varchar(255) DEFAULT NULL,
  stu_grade varchar(255) DEFAULT NULL,
  PRIMARY KEY (stu_id)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
##中间表
CREATE TABLE sch_student_course (
  stu_id bigint(20) NOT NULL,
  cou_id bigint(20) NOT NULL,
  PRIMARY KEY (stu_id,cou_id),
  KEY `FK_stu_cou_stu_id` (cou_id),
  CONSTRAINT `FK_stu_cou_cou_id` FOREIGN KEY (stu_id) REFERENCES sch_student (stu_id)  ON DELETE NO ACTION ON UPDATE NO ACTION,
  CONSTRAINT `FK_stu_cou_stu_id` FOREIGN KEY (cou_id) REFERENCES sch_course (cou_id)  ON DELETE NO ACTION ON UPDATE NO ACTION
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

2、如何在实体类中表明对应数据库中的表的“多对多”关系
在每方各自声明一个存储对方对应的类类型的Set集合,存储对方类的对象:

package cn.company.vo;

import java.util.HashSet;
import java.util.Set;

public class Course {
	private Long id;
	private String name;
	private Integer credit;
	//声明一个存储对方对应的类类型的Set集合
	private Set<Student> students = new HashSet<Student>();
	
	//...节省篇幅,此处省略get/set方法
	
	@Override
	public String toString() {
		return "Course [id=" + id + ", name=" + name + ", credit=" + credit + "]";
	}	
}
package cn.company.vo;

import java.util.HashSet;
import java.util.Set;

public class Student {	
	private Long id;
	private String name;
	private Integer grade;
	//声明一个存储对方对应的类类型的Set集合
	private Set<Course> courses = new HashSet<Course>();
	
	//...节省篇幅,此处省略get/set方法
	
	@Override
	public String toString() {
		return "Student [id=" + id + ", name=" + name + ", grade=" + grade + "]";
	}
}

3、如何在映射文件中表明对应数据库中的表的“一对多”关系
在各自的映射文件中设置set标签:

  • set标签属性name表示当前类中声明的对方的Set集合的成员属性名称;
  • set标签属性table表示中间表的名称;
  • set标签的子标签key的column属性表示当前表在中间表中对应的外键名称;
  • set标签的子标签many-to-many的class属性表示对方对应类的全路径;
  • set标签的子标签many-to-many的column属性表示对方表在中间表中对应的外键名称。
<?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="cn.company.vo.Course" table="sch_course">
		<id name="id" column="cou_id">
			<generator class="native"/>
		</id>
		<property name="name" column="cou_name"/>
		<property name="credit" column="cou_credit"/>
		<set name="students" table="sch_student_course">
			<key column="cou_id"/>
			<many-to-many class="cn.company.vo.Student" column="stu_id"/>
		</set>
	</class>
</hibernate-mapping>
<?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="cn.company.vo.Student" table="sch_student">
		<id name="id" column="stu_id">
			<generator class="native"/>
		</id>
		<property name="name" column="stu_name"/>
		<property name="grade" column="stu_grade"/>
		<set name="courses" table="sch_student_course">
			<key column="stu_id"/>
			<many-to-many class="cn.company.vo.Course" column="cou_id"/>
		</set>
	</class>
</hibernate-mapping>

六、多对多关系的表在hibernate中的操作:

1、级联删除、保存或更新
其操作可参照一对多关系的操作,但级联删除一般不使用,因为多对多级联关系复杂,甚至有可能把整个表都给级联删除了。
2、inverse
其操作可参照一对多关系的操作,可以任意选择一方放弃外键维护权,该属性用在保存操作中时需要小心,如果一的一方即设置了级联保存又设置了放弃维护外键,执行操作之后外键将为null,因为此时外键仅由一的一方维护而一的一方却将之放弃了。
3、其他操作

  • 给某一学生增选某一课程;
  • 给某一学生改选某一课程;
  • 给某一学生删除某一课程;
发布了128 篇原创文章 · 获赞 17 · 访问量 2723

猜你喜欢

转载自blog.csdn.net/qq_43705275/article/details/104282199
今日推荐