多表映射之多对一(many-to-one)
在此以员工和部门的关系为例,员工与部门的关系是典型的多对一关系。
员工实体类:
public class Employee {
private int id;
private String name;
private Date birthday;
private Department department;
public Employee() {
super();
// TODO Auto-generated constructor stub
}
public Employee(String name, Date birthday, Department department) {
super();
this.name = name;
this.birthday = birthday;
this.department = department;
}
//...省略getter和setter方法
}
员工的映射文件
<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<!-- Generated 2017-5-18 15:46:21 by Hibernate Tools 3.5.0.Final -->
<hibernate-mapping>
<class name="com.walter.vo.Employee" table="EMPLOYEE">
<id name="id" type="int">
<column name="ID" />
<generator class="native" />
</id>
<property name="name" type="java.lang.String">
<column name="NAME" />
</property>
<property name="birthday" type="date">
<column name="BIRTHDAY" />
</property>
<!--
many-to-one:声明当前类对应的表与目标类对应的表之间是多对一的关系
name:一的一方(Department)在多的一方(Employee)的实体类中对应的属性名,也是当前类对应表中默认的外键字段,默认外键关联的是department表的主键
class:一的一方(Department)实体类的类路径
fetch:表示抓取策略,fetch="join"表示使用左链接方式查询
-->
<many-to-one name="department" class="com.walter.vo.Department" fetch="join">
<column name="DEPARTMENT" />
</many-to-one>
</class>
</hibernate-mapping>
部门实体类
public class Department {
private int id;
private String name;
//...省略构造方法和getter/setter方法
}
部门映射文件
<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<!-- Generated 2017-5-18 15:46:21 by Hibernate Tools 3.5.0.Final -->
<hibernate-mapping>
<class name="com.walter.vo.Department" table="DEPARTMENT">
<id name="id" type="int">
<column name="ID" />
<generator class="native" />
</id>
<property name="name" type="java.lang.String">
<column name="NAME" />
</property>
</class>
</hibernate-mapping>
实体类和映射文件配置完成后记得要在Hibernate核心配置文件中配置映射文件。
测试
- 工具类
public class HibernateUtil {
private static SessionFactory sessionFactory;
static{
Configuration configuration = new Configuration();
configuration.configure();
sessionFactory = configuration.buildSessionFactory();
}
public static SessionFactory getSessionFactory(){
return sessionFactory;
}
public static Session getSession(){
return sessionFactory.openSession();
}
public static void close(Session s){
if(s!=null)
s.close();
}
}
- 测试类
/**
* 增加数据
*/
public static void save(){
Session session = HibernateUtil.getSession();
Transaction transaction = session.beginTransaction();
// 创建一个部门对象
Department department = new Department("技术部");
// 创建一个员工对象,同时告知该员工对象属于哪个部门。如果在此没有设置employee的department,则该员工的外键值为null
Employee employee = new Employee("张三", new Date(), department);
Employee employee2 = new Employee("李四", new Date(), department);
/*
如果先保存一的一方(departnment),在保存多的一方(employee),只有insert语句产生。其原理是:
先保存department,department表中的主键会自动生成,然后在保存employee的时候,会自动引用department中相应的主键
*/
session.save(department);
session.save(employee);
session.save(employee2);
/*
如果先保存多的一方(employee),再保存保存一的一方(departnment),除了产生insert语句,还会在insert语句后面产生update语句。其原理是:
当我们保存员工时,由于还没有保存部门,所以员工的外键没有部门的主键可以引用,所以为null;当我们保存完部门后,会根据部门的主键对相应员工的外键进行更新操作。
*/
session.save(employee);
session.save(employee2);
session.save(department);
transaction.commit();
HibernateUtil.close(session);
}
/**
* 根据id查询数据
*/
public static Employee getById(int id){
Session session = HibernateUtil.getSession();
Employee employee = (Employee) session.get(Employee.class, 1);
/*初始化代理对象:
Hibernate.initialize(employee.getDepartment());
*/
HibernateUtil.close(session);
return employee;
}
public static void main(String[] args){
Employee employee = getById(1);
System.out.println(employee.getName());//此时name可以正常输出
/*下面代码回报错,错误信息是:Exception in thread "main" org.hibernate.LazyInitializationException: could not initialize proxy - no Session.
说明在查询雇员时默认情况下是不查询部门的,当前查询部门时session已经关闭了,才报上面的错误。
结论:在多对一关联映射中,默认情况下对一的加载时存在延迟(懒)加载的。
解决延时加载有两种办法:
1.初始化代理对象:
ibernate.initialize(employee.getDepartment());
2.在多的一方的<many-to-one>标签中配置属性lazy="false"或者fetch="join"
*/
System.out.println(employee.getDepartment()
.getName);
在此主要介绍了Hibernate中多表映射的一种,在后续文章中会继续介绍其他的映射关系。如果对Hibernate配置文件不是太清楚的小伙伴可以移步到Hibernate笔记一(Hibernate简单配置和操作)来看看。
欢迎大家讨论和指正。