重拾Hibernate框架——一对多关联
来源:互联网 发布:淘宝上衣服的来源 编辑:程序博客网 时间:2024/06/17 04:40
目录
- 目录
- 前言
- 一对多映射配置
- 创建实体类
- 让两个实体类之间相互表示
- 配置映射关系
- 配置核心配置文件
- Hibernate工具类
- 一对多关联操作
- 级联保存
- 级联删除
- 修改操作
- inverse属性
前言
这里将以公司和员工为例,其中公司与员工是一对多的关系。即一个公司拥有多个员工,一个员工属于一个公司。以下将介绍如何使用Hibernate框架配置这样一种一对多的映射关系。配置完成后,我们无需在数据库中手动建表,Hibernate框架将会为我们在对应的数据库中自动创建。
一对多映射配置
创建实体类
公司和员工
Company.java
package wm103.entity;public class Company { private Integer id; private String name; private String phone; private String mobile; 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 String getPhone() { return phone; } public void setPhone(String phone) { this.phone = phone; } public String getMobile() { return mobile; } public void setMobile(String mobile) { this.mobile = mobile; }}
Employee.java
package wm103.entity;public class Employee { private Integer id; private String name; private String gender; private String phone; 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 String getGender() { return gender; } public void setGender(String gender) { this.gender = gender; } public String getPhone() { return phone; } public void setPhone(String phone) { this.phone = phone; }}
让两个实体类之间相互表示
- 在公司实体类中表示拥有多个员工:在公司实体类中添加一个属性Set集合,用来保存多个员工对象。Hibernate中要求使用Set集合来表示“多的”一方的数据,如:
// 在公司实体类中表示多个员工:一个公司拥有多个员工 // Hibernate中要求使用Set集合来表示“多的”一方的数据 private Set<Employee> employees = new HashSet<>();
- 在员工实体类中表示所属公司:在员工实体类中直接添加一个公司对象属性。如:
// 在员工实体类中表示所属公司,一个员工只属于一个公司 private Company company;
当然除了在原来的实体类中添加相应的属性外,还需要补充对应的getter和setter方法。
配置映射关系
(1)一般情况下一个实体类将对应一个映射文件。
(2)完成实体类的映射基本配置。
(3)在映射文件中,配置一对多关系。
具体如下:
Company.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> <class name="com.wm103.entity.Company" table="t_company"> <id name="id" column="id"> <generator class="native"/> </id> <property name="name" column="name"></property> <property name="phone" column="phone"></property> <property name="mobile" column="mobile"></property> <!-- 在公司映射文件中表示所有员工:使用set标签表示所有员工。 set标签 name属性:表示公司实体类中表示所有员工的Set集合的名称 --> <set name="employees"> <!-- ** Hibernate中双向维护外键,在一和多两方都需要配置外键 ** key标签 column属性:表示在“多的”一方的表中设置的外键的名称 --> <key column="cid"></key> <!-- one-to-many标签:表示单向一对多关系 class属性:“多的”一方的实体类全路径 --> <one-to-many class="com.wm103.entity.Employee"></one-to-many> </set> </class></hibernate-mapping>
Employee.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> <class name="com.wm103.entity.Employee" table="t_employee"> <id name="id" column="id"> <generator class="native"/> </id> <property name="name" column="name"></property> <property name="gender" column="gender"></property> <property name="phone" column="phone"></property> <!-- 配置员工所属的公司 many-to-one标签:表示单向多对一关系 name属性:在员工实体类中所属公司表示的属性名称 class属性:“一的”一方的实体类全路径 column属性:数据库中外键名称,与Company的映射配置中统一 --> <many-to-one name="company" class="com.wm103.entity.Company" column="cid"></many-to-one> </class></hibernate-mapping>
配置核心配置文件
hibernate.cfg.xml(记得在运行项目前要提前创建好相应的数据库,如这里是hibernate_day02)
<?xml version='1.0' encoding='utf-8'?><!DOCTYPE hibernate-configuration PUBLIC "-//Hibernate/Hibernate Configuration DTD//EN" "http://www.hibernate.org/dtd/hibernate-configuration-3.0.dtd"><hibernate-configuration> <session-factory> <property name="connection.username">root</property> <property name="connection.password"></property> <property name="connection.driver_class">com.mysql.jdbc.Driver</property> <property name="connection.url">jdbc:mysql:///hibernate_day02?useUnicode=true&characterEncoding=UTF-8</property> <property name="dialect">org.hibernate.dialect.MySQLDialect</property> <property name="show_sql">true</property> <property name="format_sql">true</property> <property name="hbm2ddl.auto">update</property> <property name="hibernate.current_session_context_class">thread</property> <!-- **把映射文件放到核心配置文件中** --> <mapping resource="com/wm103/entity/Company.hbm.xml"/> <mapping resource="com/wm103/entity/Employee.hbm.xml"/> </session-factory></hibernate-configuration>
Hibernate工具类
HibernateUtil.java
package com.wm103.utils;import org.hibernate.Session;import org.hibernate.SessionFactory;import org.hibernate.cfg.Configuration;/** * Created by DreamBoy on 2017/5/19. */public class HibernateUtil { // 单态模式的SessionFactory private static final SessionFactory sessionFactory; static { // 采用默认的hibernate.cfg.xml来启动一个Configuration的实例 Configuration cfg = new Configuration().configure(); sessionFactory = cfg.buildSessionFactory(); } public static SessionFactory getSessionFactory() { return sessionFactory; } public static Session getSession() { return sessionFactory.getCurrentSession(); } public static void main(String[] args) { }}
一对多关联操作
以下所有测试案例,如无特殊说明均可放置在测试类HibernateDemo.java中test方法的“具体逻辑”部分处进行运行测试。
package com.wm103.hibernatetest;import com.wm103.utils.HibernateUtil;import org.hibernate.Session;import org.hibernate.SessionFactory;import org.hibernate.Transaction;public class HibernateDemo { public void test() { Session session = null; Transaction tx = null; try { session = HibernateUtil.getSession(); tx = session.beginTransaction(); // 具体逻辑 tx.commit(); } catch (Exception e) { tx.rollback(); } }}
级联保存
如:添加一条公司记录,为该公司添加多个员工。
(1)复杂实现方式
testAdd1方法具体逻辑:
// 具体逻辑Company company = new Company();company.setName("CSDN");company.setMobile("123");company.setPhone("123456789");Employee employee = new Employee();employee.setName("梦小白");employee.setGender("男");employee.setPhone("789456123");// 建立公司对象与员工对象的关系company.getEmployees().add(employee);employee.setCompany(company);session.save(company);session.save(employee);
(2)简单实现方式(常用)
- 在“一的”一方 实体类对应的映射文件中配置级联保存操作,如:
在Company.hbm.xml中的set标签,配置:
<set name="employees" cascade="save-update">
(同样地,也可以在“多的”一方配置级联保存操作,举例来说,就是员工实体类对应的映射文件配置
<many-to-one name="company" class="com.wm103.entity.Company" column="cid" cascade="save-update"></many-to-one>
后,添加员工记录时,发现数据库中没有对应的公司记录,会根据员工实体对象中的company属性的公司信息,添加一条这样的公司记录。)
- 配置完成后,级联保存操作,修改如下:(只需保存company实体类对象)
testAdd2方法具体逻辑:
// 具体逻辑Company company = new Company();company.setName("BaiDu");company.setMobile("123");company.setPhone("123456789");Employee employee = new Employee();employee.setName("DreamBoy");employee.setGender("男");employee.setPhone("789456123");company.getEmployees().add(employee);session.save(company);
级联删除
如:删除某条公司记录,需要同时删除属于该公司的所有员工记录。
- 首先在“多的”一方 实体类中配置级联删除操作,如:
在Company.hbm.xml中的set标签,配置:
<set name="employees" cascade="delete">
注:如需配置cascade属性值为多个选项,可以以英文逗号进行分隔,如:cascade="save-update,delete"
。
- 实现删除操作,只需删除company实体对象,将会自动删除该公司下的所有员工记录。
testDelete方法具体逻辑:
Company company = session.get(Company.class, 2);session.delete(company);
输入执行的SQL语句如下:
Hibernate: select company0_.id as id1_0_0_, company0_.name as name2_0_0_, company0_.phone as phone3_0_0_, company0_.mobile as mobile4_0_0_ from t_company company0_ where company0_.id=?Hibernate: select employees0_.cid as cid5_1_0_, employees0_.id as id1_1_0_, employees0_.id as id1_1_1_, employees0_.name as name2_1_1_, employees0_.gender as gender3_1_1_, employees0_.phone as phone4_1_1_, employees0_.cid as cid5_1_1_ from t_employee employees0_ where employees0_.cid=?Hibernate: update t_employee set cid=null where cid=?Hibernate: delete from t_employee where id=?Hibernate: delete from t_company where id=?
修改操作
举例:修改某一员工所属公司为另外一家公司。如:
// 具体逻辑// 1. 根据ID查询公司和员工Company company = session.get(Company.class, 3);Employee employee = session.get(Employee.class, 1);// 2. 设置持久态对象company.getEmployees().add(employee);employee.setCompany(company);// 持久状态下不需要调用session的update方法,它也能自动更新数据库
运行上述修改操作,我们会发现如下的SQL语句的输出:
Hibernate: update t_employee set name=?, gender=?, phone=?, cid=? where id=?Hibernate: update t_employee set cid=? where id=?
update了两次?!!这很明显影响了效率。原因在于Hibernate是双向维护外键的,在公司和员工中都需要维护外键,即在这里修改公司时会自动更新一次外键,修改员工时又修改了一次外键,这样造成了效率问题。解决方式:让“一的”一方不维护外键,即公司实体类不维护外键,具体设置如下。
inverse属性
在不维护外键的映射文件中进行配置,在set标签上使用inverse属性。其中inverse默认值为false,表示不放弃关系维护;值为true表示放弃关系维护。
Company.hbm.xml
<set name="employees" cascade="save-update,delete" inverse="true">
配置成功后,再进行修改操作(记得把刚修改后的结果在数据库中再改回来),执行结果输出的部分SQL语句如下:
Hibernate: update t_employee set name=?, gender=?, phone=?, cid=? where id=?
现在只执行一次update操作了!
- 重拾Hibernate框架——一对多关联
- Hibernate框架基础——一对多关联关系映射
- 重拾Hibernate框架——多对多关联
- Hibernate一对多关联映射—单向
- hibernate一对多关联映射—单向
- hibernate一对多关联映射—单向
- Hibernate一对多关联
- 精通Hibernate——映射一对多关联关系
- 精通Hibernate——建立双向一对多关联
- Hibernate(五)——一对多单向关联映射
- Hibernate映射——一对多关联映射(七)
- 007——hibernate一对多关联映射
- Hibernate映射——一对多关联映射(七)
- Hibernate映射—— 一对多关联映射
- 【Hibernate框架】关联映射(一对多,多对一)
- Hibernate框架-多对一和一对多关联
- Hibernate 一对多关联关系
- Hibernate一对多双向关联
- [iOS 密码过于简单的正则表达式]
- mysql 批量更新 update foreach
- 配置本地域名
- delphi连接access数据库的步骤(简介)
- POJ 1309 Coconuts, Revisited 笔记
- 重拾Hibernate框架——一对多关联
- java文件上传
- Java多线程入门教程
- JavaScript中的变量
- csdn的资源怎么样
- Java Filter过滤机制详解
- 了解使用 ConstraintLayout
- Json简介与转换数据例子
- 【go语言爬虫】网贷天眼数据平台爬虫