Hibernate多对多关联、inverse属性、cascade属性

多对多关联是指两表之间,每一行数据可以有多个对应关系。

举个例子,学生选课,一个学生可以选择多门课程(相当于一对多关联),同时一门课又被多个学生选择(相当于一对多关联);一个学生对应着学生表中的一条数据,而这条数据又可以对应多门课程,同样,一个课程也对应多个学生。

在hibernate中通过中间表来实现多对多关联。

下面说说在hibernate中的实现

学生实体类

public class Student {
	private Integer sid;
	private String sname;
	private String sex;
	private Set<Course> courses = new HashSet<Course>();
       //以下省略javabean方法
}

课程实体类

public class Course {
	private Integer courseId;
	private String courseName;
	private String courseDesc;
	private Set<Student> students = new HashSet<Student>();
        //以下省略javabean方法
}

Course.hbm.xml配置

<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC 
	"-//Hibernate/Hibernate Mapping DTD 3.0//EN"
	"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<hibernate-mapping package="com.hibernate.many2many.entity">
	<class name="Student">
		<id name="sid" column="SID" type="java.lang.Integer">
			<generator class="assigned"></generator>
		</id>
		<property name="sname" column="SNAME" not-null="true" type="java.lang.String"></property>
		<property name="sex" column="SEX" type="java.lang.String"></property>
                <!-- name属性指该学生实体持有课程集合,table属性指定该学生表连接哪张中间表.inverse将关联控制权交给学生表 -->
		<set name="courses" table="STUDENTCHOOSECOURSE" inverse="true">
                    <!-- column属性指连接本表的STUDENTCHOOSECOURSE中间表所关联的外键列为RESID -->
		    <key column="RESID"></key>
                    <!-- 本表关联的Course表连接中间表STUDENTCHOOSECOURSE所对应的列RECOURSEID -->
		    <many-to-many class="Course" column="RECOURSEID"></many-to-many>
		</set>
	</class>
</hibernate-mapping>

Student.hbm.xml配置

<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC 
	"-//Hibernate/Hibernate Mapping DTD 3.0//EN"
	"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<hibernate-mapping package="com.hibernate.many2many.entity">
	<class name="Student">
		<id name="sid" column="SID" type="java.lang.Integer">
			<generator class="assigned"></generator>
		</id>
		<property name="sname" column="SNAME" not-null="true" type="java.lang.String"></property>
		<property name="sex" column="SEX" type="java.lang.String"></property>
                <!-- 学生类持有课程类的集合,并且学生表和中间表STUDENTCHOOSECOURSE关联,学生实体对所有操作进行级联 -->
		<set name="courses" table="STUDENTCHOOSECOURSE" cascade="all" >
                        <!-- 中间表通过RESID关联该学生表主键 -->
			<key column="RESID"></key>
                        <!-- 学生类持有的该集合是课程类,多对多映射通过课程ID来对应到课程实体类 -->
			<many-to-many class="Course" column="RECOURSEID"></many-to-many>
		</set>
	</class>
</hibernate-mapping>

测试代码

    @Test
	public void testAdd()
	{
		Student stu1 = new Student(1, "小明", "男");
		Student stu2 = new Student(2, "小红", "女");
		Student stu3 = new Student(3, "小兰", "女");
		
		Course course1 = new Course(1003, "数学", "数学是xxxx");
		Course course2 = new Course(1210, "语文", "语文是xxxx");
		Course course3 = new Course(3212, "人工智能", "人工智能是xxxx");
		
                //11,13,22,21,31,32,33
		stu1.getCourses().add(course1);
		stu1.getCourses().add(course3);
		stu2.getCourses().add(course2);
		stu2.getCourses().add(course1);
		stu3.getCourses().add(course1);
		stu3.getCourses().add(course2);
		stu3.getCourses().add(course3);
		
		session.save(stu1);
		session.save(stu2);
		session.save(stu3);
	}

                        

依次是hibernate创建的学生表、课程表、选课表。可以看到在课程表和学生表中是没有字段与彼此对应,关联关系全通过选课表来对应。

现在来讲讲inverse="true"和cascade="all"

inverse="true"是将关联控制权交给对方,自己不维护(用以提高数据库性能)

cascade="all"指对所有操作进行级联

当我们把关联控制权交给student表的时候,应该让student表拥有级联操作,否则将导致报错:外键约束异常。

之前我不太理解inverse="true"应该放在哪里使用,于是把inverse="true"和cascade="all"放在Course.hbm.xml中,导致出现下面异常

SQL Error: 1452, SQLState: 23000
org.hibernate.exception.ConstraintViolationException: 
could not execute statement
Caused by: com.mysql.jdbc.exceptions.jdbc4.MySQLIntegrityConstraintViolationException:
Cannot add or update a child row: a foreign key constraint fails (`db_ormlearn`.`studentchoosecourse`, CONSTRAINT `FK_hk3veey6orbgaiayejlmms7uf` FOREIGN KEY (`RECOURSEID`) REFERENCES `course` (`COURSEID`))

发现是外键约束异常,查看控制台,在向student中添加数据时,始终缺少指向课程的外键courseId,于是发现many-to-many可能有问题,调试一番,解决了。哈哈。

总结:

一定要注意,inverse和cascade属性,谁在维护关联关系,那么级联操作就应该交给谁

<many-to-many>中的属性介绍

<set name="students" table="STUDENTCHOOSECOURSE"  inverse="true" >
	<!-- key标签中,column属性指定连接这张表的中间表的外键 -->
	<key column="RECOURSEID" ></key>
	<!-- class连接这张表的多方的类名,column指通过中间表的那个字段连接到这张表 -->
	<many-to-many class="Student" column="RESID"></many-to-many>
</set>

<set>中的name属性指定该hbm.xml对应的实体类所包含的集合,table表示要关联的表

<key>中的column指要关联的表通过哪个字段关联到本表。key是指外键约束

<many-to-many>指定另一张表要关联到中间表的信息。class指定另一张表的类名。column指关联到本中间表的字段

发布了21 篇原创文章 · 获赞 2 · 访问量 1万+

猜你喜欢

转载自blog.csdn.net/qq_34291570/article/details/82770303