Hibernate的关联关系映射

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的已经被删除了。 

猜你喜欢

转载自blog.csdn.net/cainame/article/details/81278347