Hibernatel框架关联映射

Hibernate程序执行流程:

1.集合映射

需求:网络购物时,用户购买商品,填写地址

每个用户会有不确定的地址数目,或者只有一个或者有很多。这个时候不能把每条地址分别放在一个字段,这样的话会非常的麻烦。

数据库设计:创建两个表,一个是保存用户信息,一个表保用户的地址。使用外键引用。javaBean对象中的地址信息使用Set集合方式。配置映射使集合能够映射到数据库

1.1.集合映射的配置和保存

集合分为Set,List,Map集合,也有数组可用,使用方法大体上是相同的,区别只是在映射配置的时候有细微的区别。下面是javaBean对象和集合映射的配置写法,以及测试类。

JavaBean对象:


/**
* User对象
*/
public class User {
private int userId;
private String userName;
//一个用户,对应的多个地址
private Set<String> address;
private List<String> addressList = new ArrayList<String>();
// private String[] addressArray;//映射方式和List一样,配置的名字换成<array name=""/>
private Map<String,String> addressMap = new HashMap<String, String>(); //set方法和get方法省略
}

映射文件的写法:

映射文件我在主文件配置了自动创建表,所以不用单独创建表了

<?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="a_collection"> <!--javabean和表的映射-->
<class name="User" table="t_user">
<!--1.主键映射-->
<id name="userId" column="id">
<generator class="native"/>
</id>
<!--2.普通字段映射-->
<property name="userName"/>
<!--
3.set集合属性映射
name:指定要映射的set集合的属性
table:集合属性要映射到的表
key:指定集合表(t_address)的外键字段
element:指定集合表的其他字段
type:元素类型,一定要指定
-->
<set name="address" table="t_address">
<key column="uid"/>
<element column="address" type="string"/>
</set> <!--
List集合映射
list-index:指定的是拍序列名称,因为要保证list集合的有序
-->
<list name="addressList" table="t_addressList">
<key column="uid"/>
<list-index column="idx"/>
<element column="address" type="string"/>
</list> <!--
Map集合的映射
key:外键字段
map-key:指定Map的key
element:指定map的value
-->
<map name="addressMap" table="t_addressMap">
<key column="uid"/>
<map-key type="string" column="shortName"/>
<element column="address" type="string"/>
</map> </class>
</hibernate-mapping>

测试类:

package a_collection;

import org.hibernate.SessionFactory;
import org.hibernate.cfg.Configuration;
import org.hibernate.classic.Session;
import org.junit.Test; import java.util.HashSet;
import java.util.Set; /**
*集合映射的测试类
*/
public class App {
private static SessionFactory sf;
static {
sf = new Configuration().configure().buildSessionFactory();
} //保存Set
@Test
public void testSaveSet() throws Exception{
Session session = sf.openSession();
session.beginTransaction(); //--保存adress
Set<String> addressSet = new HashSet<String>();
addressSet.add("广州");
addressSet.add("深圳");
//用户对象
User user = new User();
user.setUserName("Jack");
user.setAddress(addressSet); //保存到数据库
session.save(user); session.getTransaction().commit();
session.close();
} //保存List/Map
@Test
public void testSaveList() throws Exception{
Session session = sf.openSession();
session.beginTransaction(); //用户对象
User user = new User();
user.setUserName("Jack");
user.getAddressList().add("广州");
user.getAddressList().add("深圳"); //保存到数据库
session.save(user); session.getTransaction().commit();
session.close();
} //保存Map
@Test
public void testSaveMap() throws Exception{
Session session = sf.openSession();
session.beginTransaction(); //用户对象
User user = new User();
user.setUserName("Tom");
user.getAddressMap().put("A001","广州");
user.getAddressMap().put("A002","深圳"); //保存到数据库
session.save(user); session.getTransaction().commit();
session.close();
} }

1.2.集合数据的获取

/**
* 集合数据的获取
*/
public class App02 {
private static SessionFactory sf;
static {
sf = new Configuration().configure().buildSessionFactory();
} //获取
@Test
public void testGet() throws Exception{
Session session = sf.openSession();
session.beginTransaction(); //获取user对象,因为User中有set,list,map属性,所有会全部查询出来
User user = (User)session.get(User.class, 3);//及时加载 //查询用户,同时可以获取用 户关联的set,list,map集合的数据,因为有正确映射
//当使用到集合数据的时候,才向数据库发送执行的sql语句(懒加载)
System.out.println(user); session.getTransaction().commit();
session.close();
}
}

集合映射中,映射的集合元素,都是普通的类型,但是能不能为对象呢?这个时候就可以使用一对多或者多对一。

2.一对多或多对一映射(重点)

2.1.逻辑分析

需求:部门和员工的关系:

一个部门有多个员工--一对多

多个员工,属于同一个部门--多对一

数据库:有两个表,一个是员工表(id,姓名,薪水,部门外键),一个是部门表(id,部门名称),员工表中有部门表的外键。

JavaBean设计:要有两个对象,一个员工一个部门,是两个对象。

映射:

为了将数据库和JavaBean映射起来,映射配置中如果是配置一方,就只能通过一方维护到另外一方,如果要两方都能维护到另外一方,需要两方都能配置。

2.2.代码实现

创建两个JavaBean对象,一个是员工,一个是部门

/**
* 员工方对象
*/
public class Employee {
private int empId;
private String empName;
private double salary;
//员工与部门[多对一]
private Dept dept;
//省略get和set
}
/**
* 部门方对象
*/
public class Dept {
private int depId;
private String deptName;
//部门对应多个员工[一对多]
private Set<Employee> emps = new HashSet<Employee>();
//省略get和set
}

对两个JavaBean对象分别进行映射:

Employee对象的映射:Employee.hbm.xml

<?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="b_oneToMany">
<class name="Employee" table="t_employee">
<id name="empId">
<generator class="native"/>
</id>
<property name="empName" length="20"/>
<property name="salary" type="double"/> <!--
多对一关联映射配置(员工管理到部门)
1.映射的部门属性:name="dept"
2.映射的部门对象,对应的外键字段:column="dept_id"
3.部门的类型:class="Dept"
-->
<many-to-one name="dept" column="dept_id" class="Dept"/> </class>
</hibernate-mapping>

Dept的映射:Dept.hbm.xml

<?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="b_oneToMany">
<class name="Dept" table="t_dept">
<id name="depId">
<generator class="native"/>
</id>
<property name="deptName" length="20"/> <!--
一对多关联映射配置(通过部门管理到员工)
1.指定映射的集合属性:name="emps"
2.集合属性对应的集合表:table="t_employee"
3.集合表的外键字段:<key column="deptId"/>
4.集合元素的类型:<one-to-many class="Employee"/>
-->
<set name="emps" table="t_employee">
<key column="dept_id"/>
<one-to-many class="Employee"/>
</set> </class>
</hibernate-mapping>

测试类,分别从一的一方(Dept)来操作,使可以同时更新Employee;也测试从多的一方(Employee)来操作,使可以同时更新Dept

package b_oneToMany;

import org.hibernate.SessionFactory;
import org.hibernate.cfg.Configuration;
import org.hibernate.classic.Session;
import org.junit.Test; /**
* 测试类,分别从两个对象来维护表
*/
public class App {
private static SessionFactory sf;
static {
sf = new Configuration().configure().buildSessionFactory();
}
//保存,部门方维护(一的一方操作)
@Test
public void save(){
Session session = sf.openSession();
session.beginTransaction();
//部门对象
Dept dept = new Dept();
dept.setDeptName("应用开发部");
//员工对象
Employee emp_zs = new Employee();
emp_zs.setEmpName("张三");
Employee emp_ls = new Employee();
emp_ls.setEmpName("李四"); //处理关系
dept.getEmps().add(emp_zs);
dept.getEmps().add(emp_ls); session.save(emp_zs);
session.save(emp_ls);
session.save(dept);//保存部门,部门下所有的员工
session.getTransaction().commit();
session.close(); } //【推荐】保存,员工方维护(多的一方操作)
@Test
public void save2(){
Session session = sf.openSession();
session.beginTransaction();
//部门对象
Dept dept = new Dept();
dept.setDeptName("人事部");
//员工对象
Employee emp_zs = new Employee();
emp_zs.setEmpName("张三");
Employee emp_ls = new Employee();
emp_ls.setEmpName("李四"); //处理关系
emp_zs.setDept(dept);
emp_ls.setDept(dept); session.save(dept);
session.save(emp_zs);
session.save(emp_ls);
session.getTransaction().commit();
session.close(); }
}

数据的获取:

package b_oneToMany;

import org.hibernate.SessionFactory;
import org.hibernate.cfg.Configuration;
import org.hibernate.classic.Session;
import org.junit.Test; /**
* 获取数据
*/
public class appGet {
private static SessionFactory sf;
static {
sf = new Configuration().configure().buildSessionFactory();
}
//保存,部门方维护(一的一方操作)
@Test
public void get(){
Session session = sf.openSession();
session.beginTransaction(); //通过部门方,获取另外一方
Dept dept = (Dept)session.get(Dept.class, 1);
System.out.println(dept.getDeptName());
System.out.println(dept.getEmps()); // //通过员工方,获取另一方
Employee emp = (Employee) session.get(Employee.class, 1);
System.out.println(emp.getEmpName());
System.out.println(emp.getDept().getDeptName()); session.getTransaction().commit();
session.close(); }
}

总结:

在一对多与多对一的关联关系中,保存数据最好的是通过多的一方来维护关系,这样可以减少update语句的生成,从而提高Hibernate的执行效率!

配置一对多与多对一,这种叫:双向关联

只配置一对多,叫单项一对多

只配置多对一,叫单项多对一。

注意:

配置了哪一方,哪一方才有维护关联关系的权限!

3.inverse/cascade

3.1.Inverse属性

Inverse属性是在维护表之间的关联关系的时候起作用的,表示控制权是否转移,在一的一方起作用。比如在一对多的两张表中,如果更改了一个表中的主键或者删除了一个数据,那么另外一张表该如何处理呢。

Inverse的英文意思就是翻转

Inverse=false:不转账,当前方有控制权

Inverse=true:控制反转,当前方没有控制权

Inverse维护表之间的关联关系,主要从以下几个方面来维护:

1.保存数据

有影响。如果设置控制反转,即Inverse=true,然后通过部门方(一的一方)维护关联关系。在保存部门的时候,同时保存员工,数据会保存,但是关联关系不会维护,即员工表中的部门外键不会更新,为NULL。

2.获取数据

没有影响。

3.解除关联关系

有影响

Inverse=false:可以解除关联

Inverse=true:当前方(部门)没有控制权,不能接触关联

4.删除数据对关联关系的影响

有影响

Inverse=false:有控制权,可以删除。先清空外键作用,再删除数据

Inverse=true:没有控制权,如果删除的记录有被外键引用,会报错,违反主键引用约束!如果删除的记录没有被引用,可以直接删除。

3.2.CasCade属性

CasCade表示级联操作,可以设置到一的一方或多的一方。

CasCade的参数:

none:不级联操作,默认值

save-update:级联保存或更新

delete:级联删除

save-update,delete.级联保存,更新,删除

all :同上,级联保存,更新,删除

4.多对多映射

4.1.多对多映射配置

需求:项目(Project)与开发人员(Developer)

一个项目,有多个开发人员

一个开发人员,参与多个项目!--多对多

例子:

项目1:电商系统,参与的开发人员:曹吉,王春;

项目2:OA系统,王春,老张

例子中有两个项目,开发人员王春同时参与了两个项目。

这个例子中,项目与开发人员就是多对多的关系。

数据库设计:

数据库设计如上,分析:

DB设计:数据库有项目表(t_project),包含id,项目名,日期字段。员工表(t_developer),包含id,员工姓名。这两个表是多对多的关系,一般会有个中间表(t_relation),分别填写两张表的外键,使其联系起来。中间表跟其他两个表之间的关系是一对多的关系

JavaBean:两个对象,分别是项目和开发者。项目中要有开发者的集合对象。开发者中也要有项目的集合对象。

映射:映射的配置要注意一些关键点

代码实现

首先是JavaBean对象,有两个,项目(Project)和开发者员工(Developer)

/**
* 项目
*/
public class Project {
private int prj_id;
private String prj_name;
//项目下的多个员工
private Set<Developer> developers = new HashSet<Developer>();
//省略get和set
}
/**
* 开发人员
*/
public class Developer {
private int d_id;
private String d_name;
//开发者参数的多个项目
private Set<Project> projects = new HashSet<Project>();
//省略get和set
}

然后是映射的配置,因为有两个JavaBean对象,所有也需要有两个映射文件

Project.hbm.xml

<?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="c_many2many">
<class name="Project" table="t_project">
<id name="prj_id">
<generator class="native"/>
</id>
<property name="prj_name" length="20"/> <!--
多对多映射:
1.映射的集合属性:name="developers"
2.集合属性,对应的中间表:table="t_relation"
3.在中间表中的外键字段:<key column="prjId"/>
4.3中的外键字段对应的中间表字段:column="did"
5.集合属性元素的类型:class="Developer"
-->
<set name="developers" table="t_relation">
<key column="prjId"/>
<many-to-many column="did" class="Developer"/>
</set> </class>
</hibernate-mapping>

Developer.hbm.xml

<?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="c_many2many">
<class name="Developer" table="t_developer">
<id name="d_id">
<generator class="native"/>
</id>
<property name="d_name" length="20"/> <!--
多对多映射:员工方
name:指定映射的集合属性
table:集合属性对应的中间表
key:指定中间表的外键字段(引用当前表t_developer主键的外键字段)
many-to-many:
column:指定外键字段对应的项目字段
class:集合元素的类型
-->
<set name="projects" table="t_relation">
<key column="did"/>
<many-to-many column="prjId" class="Project"/>
</set> </class>
</hibernate-mapping>

测试类:

package c_many2many;

import b_oneToMany.Dept;
import b_oneToMany.Employee;
import org.hibernate.SessionFactory;
import org.hibernate.cfg.Configuration;
import org.hibernate.classic.Session;
import org.junit.Test; /**
* 测试类
*/
public class App {
private static SessionFactory sf;
static {
sf = new Configuration().configure().buildSessionFactory();
} //多对多数据保存
@Test
public void save(){
Session session = sf.openSession();
session.beginTransaction();
/*
模拟数据:
电商系统(曹吉,王春)
OA系统(王春,老张)
*/
//创建项目对象
Project prj_ds = new Project();
prj_ds.setPrj_name("电商系统");
Project prj_oa = new Project();
prj_oa.setPrj_name("OA系统"); //创建开发者对象
Developer dev_cj = new Developer();
dev_cj.setD_name("曹吉");
Developer dev_wc = new Developer();
dev_wc.setD_name("王春");
Developer dev_lz = new Developer();
dev_lz.setD_name("老张"); //关系【项目方操作】
prj_ds.getDevelopers().add(dev_cj);
prj_ds.getDevelopers().add(dev_wc);//电商系统:曹吉,王春 prj_oa.getDevelopers().add(dev_wc);
prj_oa.getDevelopers().add(dev_lz);//OA系统:王春,老张 // //关系【开发者方】
// //注意可以在项目方维护员工方,也可以通过员工方维护项目方,不用在两方同时维护,只需要维护一方就可以了
// dev_cj.getProjects().add(prj_ds);
// dev_wc.getProjects().add(prj_ds);
// dev_wc.getProjects().add(prj_oa);
// dev_lz.getProjects().add(prj_oa); //保存
session.save(prj_ds);
session.save(prj_oa); //使用级联映射保存,在项目方维护时,员工方就不需要再写保存
//级联必须设置:cascade="save-update"
// session.save(dev_cj);
// session.save(dev_wc);
// session.save(dev_lz); session.getTransaction().commit();
session.close();
} @Test
public void bak(){
Session session = sf.openSession();
session.beginTransaction(); session.getTransaction().commit();
session.close();
}
}

4.2.多对多关联关系的维护

关联关系一般只需要在一方进行维护,不用在两方都设置。

设置Inverse属性,在多对多中维护关联关系的影响?

其实多对多中和一对多和多对一的功作用是相同的。

1.保存数据

有影响

Inverse=false,有控制权,可以维护关联关系,保存数据的时候会把对象关系插入中间表

Inverse=true 没有控制权,不会往中间表插入数据

2.获取数据

无影响

3.解除关系

有影响:

Inverse=false:有控制权,解除关系就是删除中间表的数据

Inverse=true:没有控制权,不能解除关系

4.删除数据

有影响:

Inverse=false:有控制权,先删除中间表数据,再删除自身

Inverse=true:没有控制权,如果删除的数据有被引用,会报错!否则,才可以删除

Hibernatel框架关联映射的更多相关文章

  1. Hibernate框架--关联映射,一对多,多对多 inverse cascade

    回顾Hibernate: 1. hibernate开发环境搭建 ----> 引入jar: hibernate.jar + required + jpa + 驱动包 ---> hiberna ...

  2. Java三大框架之——Hibernate关联映射与级联操作

    什么是Hibernate中的关联映射? 简单来说Hibernate是ORM映射的持久层框架,全称是(Object Relational Mapping),即对象关系映射. 它将数据库中的表映射成对应的 ...

  3. SSM框架开发web项目系列(三) MyBatis之resultMap及关联映射

    前言 在上篇MyBatis基础篇中我们独立使用MyBatis构建了一个简单的数据库访问程序,可以实现单表的基本增删改查等操作,通过该实例我们可以初步了解MyBatis操作数据库需要的一些组成部分(配置 ...

  4. (转)MyBatis框架的学习(五)——一对一关联映射和一对多关联映射

    http://blog.csdn.net/yerenyuan_pku/article/details/71894172 在实际开发中我们不可能只是对单表进行操作,必然要操作多表,本文就来讲解多表操作中 ...

  5. 【Hibernate框架】关联映射(多对多关联映射)

    按着我们的总结行进计划,接下来,就是有关于多对多映射的总结了. 我们来举个例子啊,很长时间以来,房价暴涨不落,但是还有很多人拥有很多套房产,假如说,一个富豪拥有九套房产,家里人么准去住哪一套,我们就以 ...

  6. 【Hibernate框架】关联映射(一对多,多对一)

    根据我们的总结计划,上篇文章我们总结了有关于一对一映射相关知识,接下来,我们进行下一个阶段,一对多.多对一映射相关知识. 场景设定: 国家规定,一个人只能在一个公司上班,一个公司可以拥有很多员工.我们 ...

  7. 【Hibernate框架】关联映射(一对一关联映射)

    一.整理思路: 之前,小编总结过Mybatis的关联映射,接下来,再来总结一下hibernate的相关的关联映射,直接上图: 这张图,就是小编整理总结整个Hibernate的关联映射的一个大致思路. ...

  8. Hibernate框架之关联映射入门

    关联映射就是将关联关系映射到数据库里,在对象模型中就是一个或多个引用. 一:配置单向多对一关联 在Emp类中定义一个Dept属性,而在Dept类中无须定义用于存放Emp对象的集合属性 01.Dept. ...

  9. ORM框架Hibernate (四) 一对一单向、双向关联映射

    简介 在上一篇博客说了一下多对一映射,这里再说一下一对一关联映射,这种例子在生活中很常见,比如一个人的信息和他的身份证是一对一.又如一夫一妻制等等. 记得在Java编程思想上第一句话是“一切皆对象”, ...

随机推荐

  1. 【.net 深呼吸】细说CodeDom(1):结构大观

    CodeDom 是啥东东?Html Dom听过吧,XML Dom听过吧.DOM一般可翻译为 文档对象模型,那 Code + DOM呢,自然是指代码文档模型了.如果你从来没接触过 CodeDom,你大概 ...

  2. css3中perspective

    perspective 属性定义 3D 元素距视图的距离,以像素计.该属性允许改变 3D 元素查看 3D 元素的视图.当为元素定义 perspective 属性时,其子元素会获得透视效果,而不是元素本 ...

  3. ASP.NET MVC5+EF6+EasyUI 后台管理系统(66)-MVC WebApi 用户验证 (2)

    系列目录 前言: 回顾上一节,我们利用webapi简单的登录并进行了同域访问与跨域访问来获得Token,您可以跳转到上一节下载代码来一起动手. 继续上一篇的文章,我们接下来演示利用拿到的Token来访 ...

  4. 学习ASP.NET Core,怎能不了解请求处理管道[2]: 服务器在管道中的“龙头”地位

    ASP.NET Core管道由注册的服务器和一系列中间件构成.我们在上一篇中深入剖析了中间件,现在我们来了解一下服务器.服务器是ASP .NET Core管道的第一个节点,它负责完整请求的监听和接收, ...

  5. Linux平台 Oracle 10gR2(10.2.0.5)RAC安装 Part2:clusterware安装和升级

    Linux平台 Oracle 10gR2(10.2.0.5)RAC安装 Part2:clusterware安装和升级 环境:OEL 5.7 + Oracle 10.2.0.5 RAC 3.安装Clus ...

  6. fir.im Weekly - 关于 iOS10 适配、开发、推送的一切

    "小程序"来了,微信变成名副其实的 Web OS,新一轮的Web App 与Native App争论四起.程序员对新技术永远保持灵敏的嗅觉和旺盛的好奇心,@李锦发整理了微信小程序资 ...

  7. YII 2.x 模板文件的 beginBlock、beginContent、beginCache

    echo '-----------beginBlock--------------------- <br />'; $this->beginBlock('block1', false ...

  8. linux练习题

    观察系统当前进程的运行情况的命令是( ):A.freeB.dmesgC.topD.last 答案:http://hovertree.com/tiku/bjag/foxg5n0q.htm Linux系统 ...

  9. Win10命令提示符(cmd)怎么复制粘贴

    在Win10系统里右键开始菜单,选择弹出菜单里的命令提示符,如下图所示: 然后复制要粘贴的文字,例如: echo hovertree.com 把上面的文字复制后,点击命令提示符窗口,然后在命令提示符窗 ...

  10. Java中的进程和线程

     Java中的进程与线程 一:进程与线程 概述:几乎任何的操作系统都支持运行多个任务,通常一个任务就是一个程序,而一个程序就是一个进程.当一个进程运行时,内部可能包括多个顺序执行流,每个顺序执行流就是 ...