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的已经被删除了。
上一篇: Hibernate:对象关联关系映射