学习笔记,为了加强记忆和深入理解在此记录备忘。如有错误和理解不当之处,还望指正。万分感谢!
另外,实例和内容有些是参照网络其他博文,如有侵权可联系删除。
参考博文:https://www.cnblogs.com/biehongli/p/6561690.html
学习重点:
1、学习Hibernate一对多和多对一的配置
set元素和many-to-one元素的配置
2、学习关联关系及保存顺序
关系维护:数据最好通过多的一方维护,这样可以减少update sql;
保存顺序:保存的顺序最好是先保存一的一方再保存多的一方,提高效率,少执行update sql语句
以员工和部门为例:
一个部门包含多个员工【一对多映射】
多个员工属于一个部门【多对一映射】
一、关于单向和双向
关于单向和双向区别
单向:主表更新,从表更新。从表更新,主表不管。主表可以查询到从表内容,从表不能查询主表内容
双向:更新一张表,另一张表中与之相关联的数据都进行更新,两张表都可以相互查询
关于单向和双向实体类的区别(一对多)
单向:部门实体类引入了员工对象的集合属性 ;员工实体类正常
双向:部门实体类引入了员工对象的集合属性 ;员工实体类引入老师的对象;
关于单向和双向映射文件的区别(一对多)
单向:部门对象的映射引入one-to-many元素配置;员工对象的映射文件正常无需额外配置
双向:部门对象的映射引入one-to-many元素配置;员工对象的映射文件引入many-to-one元素配置
双向是在单向的基础上增加配置,一对多双向反过来就是多对一双向。以下示例为双向一对多
一对多 | 单向(一) | 双向(一) | 单向(多) | 双向(多) |
实体类 | 除了自己的属性外增加多的一方对象集合 private Set<Employee> emps; | 除了自己的属性外增加了多方对象集合 private Set<Employee> emps; | 只有自己的属性,没有其他 | 除了自己的属性外,增加了一方的对象 private Dept dept; |
映射文件 | 增加了set元素 <set name="emps" table="t_employee"> | 增加了set元素 <set name="emps" table="t_employee"> | 只有自己的映射关系,没有其他 | 增加many-to-one元素 <many-to-one |
二、一对多(多对一)
部门Dept实体类
package demo.entity;
import java.util.Set;
/*
* 关键点是通过部门实体类维护到员工的实体类
*/
public class Dept {
private int deptId;// 部门编号
private String deptName;// 部门名称
private Set<Employee> emps;// 部门对应多个员工,即一对多的关系
// private Set<Employee> emps = new HashSet<>();//方便赋值,这里可以直接创建实例化
public int getDeptId() {
return deptId;
}
public void setDeptId(int deptId) {
this.deptId = deptId;
}
public String getDeptName() {
return deptName;
}
public void setDeptName(String deptName) {
this.deptName = deptName;
}
public Set<Employee> getEmps() {
return emps;
}
public void setEmps(Set<Employee> emps) {
this.emps = emps;
}
}
Employee实体类
package demo.entity;
public class Employee {
private int empId;// 员工的编号
private String empName;// 员工的名称
private double salary;// 员工的薪资
private Dept dept;// 员工和部门的关系
public int getEmpId() {
return empId;
}
public void setEmpId(int empId) {
this.empId = empId;
}
public String getEmpName() {
return empName;
}
public void setEmpName(String empName) {
this.empName = empName;
}
public double getSalary() {
return salary;
}
public void setSalary(double salary) {
this.salary = salary;
}
public Dept getDept() {
return dept;
}
public void setDept(Dept dept) {
this.dept = dept;
}
}
Dept映射文件
<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC
"-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd">
<hibernate-mapping package="demo.entity">
<class name="Dept" table="t_dept">
<!-- 第一写主键映射 -->
<id name="deptId" column="deptId">
<generator class="native" />
</id>
<!-- 第二写其他字段映射 -->
<property name="deptName" column="deptName"
length="20" type="string" />
<!--
第三写其他映射,比如这里的set集合映射,set集合映射主要有以下几点:
1 实体类申明的集合属性属性(name)
2 集合属性对应的表(table)
3 指定集合表的外键字段名称(key中的column)
4 集合对象对应的实体类(noe-to-many中的class)
-->
<set name="emps" table="t_employee">
<!--column指定了员工表的外键字段名称 -->
<key column="deptId"></key>
<!-- class由于上面已经写了包名,这里直接使用即可 -->
<one-to-many class="Employee" />
</set>
</class>
</hibernate-mapping>
Employee映射文件
<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC
"-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd">
<hibernate-mapping package="demo.entiey">
<class name="Employee" table="employee">
<!-- 主键映射 -->
<id name="empId" column="empId">
<generator class="native"></generator>
</id>
<!-- 其他字段映射 -->
<property name="empName" column="empName" length="20" type="string"/>
<property name="salary" column="salary" type="double" />
<!--
多对一的映射配置:
name是实体类中申明的属性;
column外键字段名称;
class对应的部门实体类;
-->
<many-to-one name="dept" column="deptId" class="Dept" />
</class>
</hibernate-mapping>
测试
package demo.test;
import java.util.HashSet;
import java.util.Set;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.Transaction;
import org.hibernate.cfg.Configuration;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import demo.entity.Dept;
import demo.entity.Employee;
class JunitTest {
private Configuration configuration = new Configuration().configure();
private SessionFactory sFactory = configuration.buildSessionFactory();
private Session session = null;
private Transaction transaction = null;
@BeforeEach
void setUp() throws Exception {
session = sFactory.openSession();
transaction = session.beginTransaction();
}
@AfterEach
void tearDown() throws Exception {
transaction.commit();
session.close();
}
@Test
void testSave() {
// 实例化部门和员工
Dept dept1 = new Dept();
dept1.setDeptName("人事部");
Dept dept2 = new Dept();
dept2.setDeptName("技术部");
Employee employee1 = new Employee();
employee1.setEmpName("员工1");
employee1.setSalary(1000);
Employee employee2 = new Employee();
employee2.setEmpName("员工2");
employee2.setSalary(2000);
Employee employee3 = new Employee();
employee3.setEmpName("员工3");
employee3.setSalary(3000);
Employee employee4 = new Employee();
employee4.setEmpName("员工4");
employee4.setSalary(4000);
// 通过部门(一)设置员工(多)【不推荐】
Set<Employee> employees = new HashSet<>();
employees.add(employee1);
employees.add(employee2);
dept1.setEmps(employees);
// 通过员工(多)设置部门(一)【推介】
employee3.setDept(dept2);
employee4.setDept(dept2);
// 数据最好通过多的一方维护,这样可以减少update sql
// 保存的顺序最好是先保存一的一方再保存多的一方,提高效率,少执行update sql语句
// 【不推介】
session.save(employee1);
session.save(employee2);
session.save(dept1);
// 【推介】
session.save(dept2);
session.save(employee3);
session.save(employee4);
}
}
把映射文件加入到配置文件中
<mapping resource="demo/entity/Dept.hbm.xml"/>
<mapping resource="demo/entity/Employee.hbm.xml"/>