欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

Hibernate的关联关系映射

程序员文章站 2022-04-22 18:04:13
...

1.三种关联关系

一对一:在任意一方引入对方的主键作为外键

一对多:在"多"的一方,添加"一"的一方的主键作为外键

多对多:产生中间关系表,引入两张表的主键作为外键,两个主键成为联合主键。

2.一对多关联映射

在一个A对应多个B的情况下,需要在A类以Set集合的方式引入B类类型的对象,在B类定义A的属性,在“多”的一方的数据表中增加一个外键,指向“一”的一方的数据表的主键。

Student.java(多)

public class Student {
private Integer id;
private String name;
private Grade grade;
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 Grade getGrade() {
	return grade;
}
public void setGrade(Grade grade) {
	this.grade = grade;
}
}

Grade.java(一)

public class Grade {
private Integer id;
private String name;
//引入"多"的一方的对象
private Set<Student> students=new HashSet<Student>();
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<Student> getStudents() {
	return students;
}
public void setStudents(Set<Student> students) {
	this.students = students;
}
}

3.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 package="com.wsyu.txt.pojo.user">
	<class name="Student" table="student">
		<id name="id">
			<generator class="native"/>
		</id>
	<property name="name" column="name" type="string"/>
	<!--多对一的关系映射,,name是Student类里面grade属性,class表示映射的类,column是表示表中的外键名-->
    <many-to-one name="grade" class="com.wsyu.txt.pojo.user.Grade" column="gid"/>
	
	
	</class>
</hibernate-mapping>

 

 4.Grade.hbm.xml

<!DOCTYPE hibernate-mapping PUBLIC
        "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
        "http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd">
<hibernate-mapping package="com.wsyu.txt.pojo.user">
	<class name="Grade" table="grade">
		<id name="id">
			<generator class="native"/>
		</id>
	<property name="name" column="name" type="string"/>
	<!--一对多的关系使用set集合引入对象-->
	<set name="students">
        <!--确定关联的外键列-->
	<key column="gid"/>
        <!--描述持久化类的一对多关联,class是表示映射的关联类-->
        <one-to-many class="com.wsyu.txt.pojo.user.Student"/>
	</set>
	</class>
</hibernate-mapping>

 主配置文件 hibernate.cfg.xml

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE hibernate-configuration PUBLIC
"-//Hibernate/Hibernate Configuration DTD 3.0//EN"
"http://www.hibernate.org/dtd/hibernate-configuration-3.0.dtd">
<hibernate-configuration>
	<session-factory>
		<!-- 数据库方言,5版本建议按下面的语法写 -->
		<property name="hibernate.dialect">org.hibernate.dialect.MySQL5InnoDBDialect</property>
		<!-- 数据库驱动 -->
		<property name="hibernate.connection.driver_class">com.mysql.cj.jdbc.Driver</property>
		<!-- 数据库连接信息 -->
		<property name="hibernate.connection.url">
 <![CDATA[jdbc:mysql://localhost:3306/test?useUnicode=true&characterEncoding=utf8&useSSL=false&serverTimezone=Hongkong&autoReconnect=true]]></property>
		<property name="hibernate.connection.username">root</property>
		<property name="hibernate.connection.password">123456</property>
		<!-- 打印SQL语句 -->
		<property name="hibernate.show_sql">false</property>
		<!-- 不格式化SQL语句 -->
		<property name="hibernate.format_sql">false</property>
		<!-- 为Session指定一个自定义策略 -->
		<property name="hibernate.current_session_context_class">thread</property>
		<!-- C3P0 JDBC连接池 -->
	    <property name="connection.provider_class">org.hibernate.c3p0.internal.C3P0ConnectionProvider</property>
	    <!-- 在连接池中可以用的数据库连接的最少数目 -->
	    <property name="c3p0.min_size">5</property>
	    <!-- 在连接池所有数据库连接的最大数目 -->
	    <property name="c3p0.max_size">20</property>
	    <!-- 设定数据库连接过期时间,以ms计算,如果连接池中的某个数据库连接空闲状态的时间 -->
	    <property name="c3p0.timeout">120</property>
	    <!-- 每3000s检查连接池中的空闲连接 -->
	    <property name="c3p0.idle_test_period">3000</property>
            <!--根据实体类自动生成数据表,自动策略配置
            <property name="hbm2ddl.auto">update</property>  
		
		<!-- 映射文件 -->

		<mapping resource="com/wsyu/txt/pojo/user/Grade.hbm.xml"/>
		<mapping resource="com/wsyu/txt/pojo/user/Student.hbm.xml"/>
		
	</session-factory>
	</hibernate-configuratio

测试类 test.java

public class test {
	@Test
	public void test() {
		Configuration config=new Configuration().configure();
		SessionFactory sessionFactory=config.buildSessionFactory();
		Session session=sessionFactory.openSession();//得到Session对象
		Transaction transaction=session.beginTransaction();//开启事务
	    Grade g=new Grade();
	    Student s=new Student();
	    Student s2=new Student();
	    g.setName("一班");
	   s.setName("张三");
	   s2.setName("李四");
	  s.setGrade(g);
	  s2.setGrade(g);
	  g.getStudents().add(s2);
	
	  g.getStudents().add(s);
	  session.save(g);
	  session.save(s2);
	  session.save(s);
	  transaction.commit();
	  session.close();
	  sessionFactory.close();
	}
   
}

 单元测试后,成功完成映射。

3.多对多关联映射

在A类里定义B类型的Set集合,在B类里定义A类的Set集合

多对多的关系都会产生一个中间表,两张表的主键成了中间表的外键

Student.java

package com.wsyu.txt.pojo.user;

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

public class Student {
private Integer id;
private String name;
private Set<Course> course=new HashSet<Course>();

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<Course> getCourse() {
	return course;
}
public void setCourse(Set<Course> course) {
	this.course = course;
}

课程实体类


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

public class Course {
private Integer id;
private String cname;
private Set<Student> student=new HashSet<Student>();
public Integer getId() {
	return id;
}
public void setId(Integer id) {
	this.id = id;
}
public String getCname() {
	return cname;
}
public void setCname(String cname) {
	this.cname = cname;
}
public Set<Student> getStudent() {
	return student;
}
public void setStudent(Set<Student> student) {
	this.student = student;
}


}

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 package="com.wsyu.txt.pojo.user">
	<class name="Student" table="student">
		<id name="id">
			<generator class="native"/>
		</id>
	<property name="name" column="name" type="string"/>
	<!-- set表示被映射的类中的Set集合,table表示中间表的名称,key是描述Student表在中间表外键的名称 -->
	<set name="course" table="s_c">
	<key column="sid"/>
	<!-- 表示两个持久化类多对多的关联关系,其中column是course表在中间表外键的名称 -->
	<many-to-many class="com.wsyu.txt.pojo.user.Course" column="cid"/>
	</set>
	
	
	</class>
</hibernate-mapping>

Course.hbm.xmll

<?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 package="com.wsyu.txt.pojo.user">
	<class name="Course" table="couse">
		<id name="id">
			<generator class="native"/>
		</id>
	<property name="cname" column="cname" type="string"/>
	<!-- set表示被映射的类中的Set集合,table表示中间表的名称,key是描述Course表在中间表外键的名称 -->
	<set name="student" table="s_c">
	<key column="cid"/>
	<!-- 表示两个持久化类多对多的关联关系,其中column是course表在中间表外键的名称 -->
	<many-to-many class="com.wsyu.txt.pojo.user.Student" column="sid"/>
	</set>
	
	
	</class>
</hibernate-mapping>

核心配置文件

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE hibernate-configuration PUBLIC
"-//Hibernate/Hibernate Configuration DTD 3.0//EN"
"http://www.hibernate.org/dtd/hibernate-configuration-3.0.dtd">
<hibernate-configuration>
	<session-factory>
		<!-- 数据库方言 -->
		<property name="hibernate.dialect">org.hibernate.dialect.MySQL5InnoDBDialect</property>
		<!-- 数据库驱动 -->
		<property name="hibernate.connection.driver_class">com.mysql.cj.jdbc.Driver</property>
		<!-- 数据库连接信息 -->
		<property name="hibernate.connection.url"><![CDATA[jdbc:mysql://localhost:3306/test?useUnicode=true&characterEncoding=utf8&useSSL=false&serverTimezone=Hongkong&autoReconnect=true]]></property>
		<property name="hibernate.connection.username">root</property>
		<property name="hibernate.connection.password">123456</property>
		<!-- 打印SQL语句 -->
		<property name="hibernate.show_sql">false</property>
		<!-- 不格式化SQL语句 -->
		<property name="hibernate.format_sql">false</property>
		<!-- 为Session指定一个自定义策略 -->
		<property name="hibernate.current_session_context_class">thread</property>
		<!-- C3P0 JDBC连接池 -->
	    <property name="connection.provider_class">org.hibernate.c3p0.internal.C3P0ConnectionProvider</property>
	    <!-- 在连接池中可以用的数据库连接的最少数目 -->
	    <property name="c3p0.min_size">5</property>
	    <!-- 在连接池所有数据库连接的最大数目 -->
	    <property name="c3p0.max_size">20</property>
	    <!-- 设定数据库连接过期时间,以ms计算,如果连接池中的某个数据库连接空闲状态的时间 -->
	    <property name="c3p0.timeout">120</property>
	    <!-- 每3000s检查连接池中的空闲连接 -->
	    <property name="c3p0.idle_test_period">3000</property>
		<!-- 映射文件 -->
		<property name="hbm2ddl.auto">update</property>  
		
		
		<mapping resource="com/wsyu/txt/pojo/user/Grade.hbm.xml"/>
		<mapping resource="com/wsyu/txt/pojo/user/Student.hbm.xml"/>
		<mapping resource="com/wsyu/txt/pojo/user/Course.hbm.xml"/>
	</session-factory>
	</hibernate-configuration>

 测试类 test.java

package com.wsyu.txt.pojo.user.dao;

import java.util.Set;

import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.Transaction;
import org.hibernate.cfg.Configuration;
import org.junit.Test;

import com.wsyu.txt.pojo.user.Course;

import com.wsyu.txt.pojo.user.Student;

public class test {
	@Test
	public void test() {
		Configuration config=new Configuration().configure();
		SessionFactory sessionFactory=config.buildSessionFactory();
		Session session=sessionFactory.openSession();//得到Session对象
		Transaction transaction=session.beginTransaction();//开启事务

	    Student s1=new Student();
	    Student s2=new Student();
	    Course course1=new Course();
	    Course course2=new Course();
	    
	    s1.setName("张三");
	    s2.setName("李四");
	    course1.setCname("数学");
	    course2.setCname("语文");
	    
	    
	   s1.getCourse().add(course2);
	   s1.getCourse().add(course1);
	   s2.getCourse().add(course1);
	   s2.getCourse().add(course2);
	   session.save(course1);
	   session.save(course2);
	   session.save(s1);
	   session.save(s2);
	   transaction.commit();
	  session.close();
	  sessionFactory.close();
	}
   
}

单元测试后可以正常映射 

4.关联关系中的反转和级联

在Hibernate的关联关系中,可以使用单向关联,也可以使用双向关联。

在双向关联的关系中,Hibernate会同时控制双方的关系,这样在程序操作时,很容易出现重复操作。

hibernate提供类反转操作,同时在操纵多表时,主表操作后的数据能与关联表保持一致,hibernate还提供了级联操作。

一般的将一的一方的inverse属性为true,由多的一方管理关系。

public class test {
	@Test
	public void test() {
		Configuration config=new Configuration().configure();
		SessionFactory sessionFactory=config.buildSessionFactory();
		Session session=sessionFactory.openSession();//得到Session对象
		Transaction transaction=session.beginTransaction();//开启事务

	    Student s1=new Student();
	    Student s2=new Student();
	    Course course1=new Course();
	    Course course2=new Course();
	    
	    s1.setName("张三");
	    s2.setName("李四");
	    course1.setCname("数学");
	    course2.setCname("语文");
	    
	    
	   s1.getCourse().add(course2);
	   s1.getCourse().add(course1);
	   s2.getCourse().add(course1);
	   s2.getCourse().add(course2);
	   
	   
	   
	   course1.getStudent().add(s1);
	   course2.getStudent().add(s1);
	   course1.getStudent().add(s2);
	   course2.getStudent().add(s2);
	   
	   session.save(course1);
	   session.save(course2);
	   session.save(s1);
	   session.save(s2);
	   transaction.commit();
	  session.close();
	  sessionFactory.close();
	}
   
}

同时关联的话会保错。

<set name="course" table="s_c" inverse="true">

将一方反转后就不会报错了 

级联操作

当主控方在执行任意操作时,其关联对象也执行相同的操作,保持同步oascade属性

一对多级联

public void test() {
		Configuration config=new Configuration().configure();
		SessionFactory sessionFactory=config.buildSessionFactory();
		Session session=sessionFactory.openSession();//得到Session对象
		Transaction transaction=session.beginTransaction();//开启事务
                Grade grade=new Grade();
                grade.setName("二班");
                Student student=new Student();
                student.setName("王五");
                grade.getStudent.add(student);
                session.save(grade); //只保存班级
                transaction.commit();
                session.close;
                sessionFactory.close();
                
}

将Grade.hbm.xml cscade属性设置为save-update

<set name="student" table="s_c" cascade="save-update">

执行之后发现都保存了

 

一对多的级联删除操作 

<set name="student" table="s_c" cascade="delete">

 删除班级的同时也删除与其关联的student表中的数据。

孤儿删除

当一方被删除时,其所关联的外键被设置为null,这样将称为孤儿。

Grade grade=(Grade)session.get(Grade.class,4);  //查询班级为4
Student student=(Student)session.get(Student.class,5); //查询学生为5
grade.getStudents().remove(student); //解除他们的关系


<set name="student" cascade="delete-orphan">

运行之后发现学生为4的和班级为4的还在,但是学生为5的已经被删除了。