三大框架 之 Hibernate查询(一对多、多对多、查询关系)
一对多
表之间关系
一对多
- 一个部门有多个员工,一个员工只能属于某一个部门
- 一个班级有多个学生,一个学生只能属于一个班级
多对多
- 一个老师教多个学生,一个学生可以被多个老师教
- 一个学生可以先择多门课程,一门课程可以被多个学生选择
- 一个用户可以选择多个角色,一个角色也可以被多个用户选择
一对一
- 一个公司只能对应一个注册地址
表之间关系建表原则
一对多
在多的一方创建一个外键,指向一的一方的主键
多对多
创建一个中间表,中间表至少有两个字段,分别作为外键指向多对多双方的主键
一对一
唯一外键对应
主键对应
一对多关系配置
建立表
创建表的 hbm.xml文件时,有外键可不创建列的映射
主表为客户(Customer),从表为联系人(Linkman)
销售联系人(linkman),一个联系人只能属于某一个客户
CREATE TABLE `linkman` (
`link_id` bigint(32) NOT NULL AUTO_INCREMENT COMMENT '联系人编号(主键)',
`link_name` varchar(16) DEFAULT NULL COMMENT '联系人姓名',
`link_cust_id` bigint(32) NOT NULL COMMENT '客户id',
`link_gender` char(1) DEFAULT NULL COMMENT '联系人性别',
`link_phone` varchar(16) DEFAULT NULL COMMENT '联系人办公电话',
`link_mobile` varchar(16) DEFAULT NULL COMMENT '联系人手机',
`link_email` varchar(64) DEFAULT NULL COMMENT '联系人邮箱',
`link_qq` varchar(16) DEFAULT NULL COMMENT '联系人qq',
`link_position` varchar(16) DEFAULT NULL COMMENT '联系人职位',
`link_memo` varchar(512) DEFAULT NULL COMMENT '联系人备注',
PRIMARY KEY (`link_id`)
) ENGINE=InnoDB AUTO_INCREMENT=3 DEFAULT CHARSET=utf8;
客户(customer),一个客户可以有多个联系人
CREATE TABLE `customer` (
`cust_id` bigint(32) NOT NULL AUTO_INCREMENT COMMENT '客户编号(主键)',
`cust_name` varchar(32) NOT NULL COMMENT '客户名称(公司名称)',
`cust_source` varchar(32) DEFAULT NULL COMMENT '客户信息来源',
`cust_industry` varchar(32) DEFAULT NULL COMMENT '客户所属行业',
`cust_level` varchar(32) DEFAULT NULL COMMENT '客户级别',
`cust_phone` varchar(64) DEFAULT NULL COMMENT '固定电话',
`cust_mobile` varchar(16) DEFAULT NULL COMMENT '移动电话',
PRIMARY KEY (`cust_id`)
) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8;
关系图
建立ORM
实体类与数据库中建立字段 与 关系
Customer 实体类(一个客户可以有多个联系人)
package com.myxq.domain;
import lombok.Getter;
import lombok.Setter;
import java.util.HashSet;
import java.util.Set;
@Getter@Setter
public class Customer {
private Long cust_id;
private String cust_name;
private String cust_source;
private String cust_industry;
private String cust_level;
private String cust_phone;
private String cust_mobile;
//建立一个客户可以有多个联系人
//放置多的一方的集合,hibernate默认使用的是Set集合
//如果使用List的话,它要对List进行排列,在表中要多建这一列,用来排序
//一般使用的都是Set集合
//现在是双向关联,从客户能查联系人,从联系人也能查客户
private Set<Linkman> linkmens = new HashSet<>();
@Override
public String toString() {
return "Customer{" +
"cust_id=" + cust_id +
", cust_name='" + cust_name + '\'' +
", cust_source='" + cust_source + '\'' +
", cust_industry='" + cust_industry + '\'' +
", cust_level='" + cust_level + '\'' +
", cust_phone='" + cust_phone + '\'' +
", cust_mobile='" + cust_mobile + '\'' +
'}';
}
}
Linkman 实体类(一个联系人只能属于一个客户)
package com.myxq.domain;
import lombok.Getter;
import lombok.Setter;
@Getter@Setter
public class Linkman {
private Long link_id;
private String link_name;
private String link_gender;
private String link_phone;
private String link_mobile;
private String link_email;
private String link_qq;
private String link_position;
private String link_memo;
private String link_cust_id;
//一个联系人只对应一个客户
private Customer customer;
@Override
public String toString() {
return "Linkman{" +
"link_id=" + link_id +
", link_name='" + link_name + '\'' +
", link_gender='" + link_gender + '\'' +
", link_phone='" + link_phone + '\'' +
", link_mobile='" + link_mobile + '\'' +
", link_email='" + link_email + '\'' +
", link_qq='" + link_qq + '\'' +
", link_position='" + link_position + '\'' +
", link_memo='" + link_memo + '\'' +
", link_cust_id='" + link_cust_id + '\'' +
", customer=" + customer +
'}';
}
}
添加配置文件
1.客户(Customer)实体类的配置文件
customer.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.myxq.domain.Customer" table="customer" >
<!--建立类属性哪一个是主键 还要跟数据库当中主键进行对象-->
<id name="cust_id" column="cust_id" >
<generator class="native"/>
</id>
<!--建立类中的普通属性与数据库当中的表字段的映射,关联-->
<property name="cust_name" column="cust_name" />
<property name="cust_source" column="cust_source"/>
<property name="cust_industry" column="cust_industry"/>
<property name="cust_level" column="cust_level"/>
<property name="cust_phone" column="cust_phone"/>
<property name="cust_mobile" column="cust_mobile"/>
<!--一对多-->
<set name="linkmens" cascade="save-update,delete" inverse="true"><!--set属性名称-->
<key column="link_cust_id"></key><!--外键-->
<one-to-many class="com.myxq.domain.Linkman"></one-to-many>
</set>
</class>
</hibernate-mapping>
2.联系人(LinkMan)实体类配置文件
linkman.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.myxq.domain.Linkman" table="linkman" >
<!--建立类属性哪一个是主键 还要跟数据库当中主键进行对象-->
<!-- 设置主键与OID的对应关系 -->
<id name="link_id" column="link_id" >
<generator class="native"/>
</id>
<!--建立类中的普通属性与数据库当中的表字段的映射 注意:外键不用设置-->
<property name="link_name" column="link_name" />
<property name="link_gender" column="link_gender"/>
<property name="link_phone" column="link_phone"/>
<property name="link_mobile" column="link_mobile"/>
<property name="link_email" column="link_email"/>
<property name="link_qq" column=" link_qq"/>
<property name="link_position" column=" link_position"/>
<property name="link_memo" column=" link_memo"/>
<!--
many-to-one:配置多对一
name:一的一方对象属性名称
class:一的一方类的全路径
column:多的一方表的外键名称
-->
<many-to-one name="customer" cascade="save-update" class="com.myxq.domain.Customer" column="link_cust_id"/>
</class>
</hibernate-mapping>
在hibernate.cfg.xml中的标签里,添加核心配置文件
<!--加载映射文件-->
<mapping resource="com/myxq/domain/customer.hbm.xml" />
<mapping resource="com/myxq/domain/linkman.hbm.xml" />
<mapping resource="com/myxq/domain/role.hbm.xml" />
<mapping resource="com/myxq/domain/user.hbm.xml" />
引入工具类
HibernateUtil.java
package com.myxq.utils;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.cfg.Configuration;
public class HibernateUtil {
public static final SessionFactory sessionFactory;
static {
//1.加载配置文件
Configuration configure = new Configuration().configure();
//configure.addResource("com/myxq/domain/Customer.hbm.xml");
//2.创建sessionFactory --JDBC 连接池
sessionFactory = configure.buildSessionFactory();
}
public static Session openSession(){
Session session = sessionFactory.openSession();
return session;
}
public static Session getCurrentSession(){
Session session = sessionFactory.getCurrentSession();
return session;
}
}
编写测试类
级联操作
问题
在两张表建立一对多关系时,如果只保存一边的对象,就会发异常
示例
什么是级联
在操作一个对象的时候,是否会操作其关联的对象。
级联分类
级联保存或更新
级联删除
级联是有方向性
在操作一的一方,是否会操作多的一方
操作多的一方时, 是否会操作一的一方
级联保存或更新
级联保存
操作的主体是谁,就要在谁的映射配置文件当中进行配置
在开始配置的set当中添加一个新的属性cascade="save-update"
在多的一方添加级联
再去运行,就不会报异常,两条记录都会被添加
在一的一方添加级联
对象导航
两方如果都加了级联,这种我们也称为双向导航
设置双向导航时,当对象存在关系时, 就会做出对应的操作
级联更新
级联删除
删除一边数据时,同时将另一边的数据一并删除
不设置级联删除
默认:先把外键改为空,然后再删除
发送的SQL语句
设置级联删除
示例代码
配置文件
在双向级联的过程当中,会产生一些多余的sql语句
原因
当双向维护时,两都都维护了外键,当做更新操作时, 两边的外键都要去修改
解决办法
1.使用单向维护
有些地方还是会有问题
2.一方放弃维护权
在一的一方放弃外键维护权
在配置文件当中添加一个inverse="false/true"
true为放弃外键维护权,false为不放弃外键维护权
cascade与inverse
cascade控制有没有关联对象
inverse控制有没有外键
示例
lazy懒加载(默认值是proxy,不自动获取外键对象)
改成false,获取外键对象
在linkman.hbm.xml
<many-to-one name="customer" class="com.myxq.domain.Customer" column="link_cust_id" lazy="false"/>
级联保存或更新(解决 瞬时对象异常,只保存一边)
在customer.hbm.xml
<set name="linkmens" cascade="save-update,delete" inverse="true">
<!--set属性名称-->
<key column="link_cust_id"></key><!--外键-->
<one-to-many class="com.myxq.domain.Linkman">
</one-to-many>
</set>
多对多
多对多关系配置
建立表
用户表,一个用户可以有多个角色
CREATE TABLE `user` (
`user_id` bigint(32) NOT NULL AUTO_INCREMENT COMMENT '用户id',
`user_code` varchar(32) NOT NULL COMMENT '用户账号',
`user_name` varchar(64) NOT NULL COMMENT '用户名称',
`user_password` varchar(32) NOT NULL COMMENT '用户密码',
`user_state` char(1) NOT NULL COMMENT '1:正常,0:暂停',
PRIMARY KEY (`user_id`)
) ENGINE=InnoDB AUTO_INCREMENT=9 DEFAULT CHARSET=utf8;
角色表,一个角色可以被多个用户选择
CREATE TABLE `role` (
`role_id` bigint(32) NOT NULL AUTO_INCREMENT,
`role_name` varchar(32) NOT NULL COMMENT '角色名称',
`role_memo` varchar(128) DEFAULT NULL COMMENT '备注',
PRIMARY KEY (`role_id`)
) ENGINE=InnoDB AUTO_INCREMENT=6 DEFAULT CHARSET=utf8;
关系图
建立ORM
- 用户
- 角色
Role.java
import lombok.Getter;
import lombok.Setter;
import java.util.HashSet;
import java.util.Set;
@Setter@Getter
public class Role {
private Long role_id;
private String role_name;
private String role_memo;
//角色下面的所有用户
private Set<User> users = new HashSet<>();
}
添加配置文件
用户
角色
在核心配置文件当中添加两个新配置
编写测试类
单向维护
双向维护
双向维护时,必须要有一方放弃外键维护
如果两边都有维护的话, 就会有重复的的记录,由于关系表是两个字段作为共同主键,不能有相同的记录
解决办法
通常都是让被动方放弃,用户选角色,角色为被动方
多对多的级联操作和一对多的级联操作是一样的
多对多的操作
关系的操作,只需要操作集合,就可以操作它们之间的关系
给用户添加一个新的角色
修改一个用户的角色
删除角色
查询方式
OID查询
什么是OID查询
- 根据对象的OID主键进行检索
OID查询方式
- get方法
- load方法
对象导航查询
什么是对象导航检索
- Hibernate根据一个已经查询到的对象,获得其关联的对象的一种查询方式
- 先查询到联系人,就可以通过联系人获取联系人所关联的客户对象
有点像级联查询
HQL
什么是HQL
- HQL查询:Hibernate Query Language,Hibernate的查询语言
- 是一种面向对象的方式的查询语言,语法类似SQL。
- 通过session.createQuery(),用于接收一个HQL进行查询方式。
- 注意:使用时,不能用*,对于表,要采用别名查询
查询
简单查询
别名查询
排序查询
条件查询
位置绑定:根据参数的位置进行绑定条件
名称绑定:把参数对应的值起一个名称 再去设置名称
投影查询
查询对象的某个或某些属性
单个属性
多个属性
查询多个属性,封装到对象当中
要在类中,提供构造方法
分页查询
统计查询
查询的结构只有一个
分组查询
多表查询
普通内连接
迫切内连接
通过hibernate将另一个对象的数据,封装该对象中
在普通内连接inner join 后添加一个关键字fetch
QBC
什么是QBC
Query By Criteria,条件查询。是一种更加面向对象化的查询的方式。
查询
简单查询
排序查询
分页查询
条件查询
条件
= eq
> gt
> = ge
< lt
<= le
<> ne
like
in
and
or
单个条件
多个条件
统计查询
离线条件查询
- 脱离Session,添加条件
- 可以在外部提前使用DetachedCriteria对象提交设置好条件
- 最后再绑定到session当中
三大框架 之 Hibernate查询(一对多、多对多、查询关系)的更多相关文章
- 2018.11.4 Hibernate中一对、多对多的关系
简单总结一下 多表关系 一对多/多对一 O 对象 一的一方使用集合. 多的一方直接引用一的一方. R 关系型数据库 多的一方使用外键引用一的一方主键. M 映射文件 一: 多: 操作: 操作管理级别属 ...
- mybatis报错:查询一对多或多对多时只返回一条数据的问题
问题: 使用映射文件实现查询一对多或多对多时只返回一条数据问题 解决方法: 导致这种情况出现的问题是因为两个表中的主键是一样所以出现了数据覆盖问题. 解决方式一:修改数据库表中的主键(这种方法比较麻烦 ...
- java框架之Hibernate(3)-一对多和多对多关系操作
一对多 例:一个班级可以有多个学生,而一个学生只能属于一个班级. 模型 package com.zze.bean; import java.util.HashSet; import java.util ...
- 三大框架 之 Hibernate框架概述(概述、配置、核心API)
目录 Hibernate框架概述 什么是框架 hibernate简介(JavaEE技术三层架构所用到的技术) hibernate是什么框架 ORM hibernate好处 Hibernate基本使用 ...
- Java_Web三大框架之Hibernate+HQL语言基础
12.1 HQL语言基础Hibernate查询语言为HQL(Hibernate Query Language),可以直接使用实体类名及属性.HQL语法类似于SQL,有SQL的关键词如select.fr ...
- java三大框架——Struts + Hibernate + Spring
Struts主要负责表示层的显示 Spring利用它的IOC和AOP来处理控制业务(负责对数据库的操作) Hibernate主要是数据持久化到数据库 再用jsp的servlet做网页开发的时候有个 w ...
- Java三大框架之——Hibernate中的三种数据持久状态和缓存机制
Hibernate中的三种状态 瞬时状态:刚创建的对象还没有被Session持久化.缓存中不存在这个对象的数据并且数据库中没有这个对象对应的数据为瞬时状态这个时候是没有OID. 持久状态:对象经过 ...
- 22Mybatis_订单商品数据模型_多对多查询以及对多对多查询的总结
之前讲了一对一,一对多查询,这篇文章讲的是多对多. 先给出需求:查询用户及用户购买商品信息. 我们由之前的文章知道,这个需求是多对多的. 还是那个终止我们的mybatis所做的不管是之前的一对一还是一 ...
- 【SSH三大框架】Hibernate基础第六篇:多对一关联关系的映射、分析及加入、查询
这里举样例用的是:部门与员工的关系. 一个部门能够相应多个员工,这就是非常明显的多对一关联关系. 我们须要建立两个实体类:员工(Employee).部门(Department) 员工类:Employe ...
随机推荐
- JS 中Json常用操作
转自: https://www.jianshu.com/p/6501b0f3124f 直接定义json var json = {"name": "小明", &q ...
- Python2 和 pip2 存在, Python3 也存在,但是 pip3 不存在的解决办法
sudo curl https://bootstrap.pypa.io/get-pip.py -o get-pip.py sudo python3 get-pip.py 输入两行命令即可
- python 内建属性
在python中创建一个类,它不仅有我们自定义的属性和方法,还有与生俱来的一些属性和方法,我们叫它内建属性. 下面是类常用内建属性列表. 常用专有属性 说明 触发方式 __init__ 构造初始化函数 ...
- mysql57重新安装后无法再次启动mysql57服务“本地计算机上的MySQL服务启动后停止。某些服务在未由其他服务或程序使用时将自动。”--解决方法
本地计算机上的MySQL服务启动后停止.某些服务在未由其他服务或程序使用时将自动. (win10,mysql5.7+) 解决方法: 第一步:查看MySQL57安装路径 只要在programData路径 ...
- gitlab及jenkins
1.安装配置gitlab服务,在gitlab新建一个仓库,配置本地密钥,并通过ssh方式拉取gitlab仓库代码 https://packages.gitlab.com/gitlab/gitlab-c ...
- System V共享内存
目录 1. 概述 2. System V共享内存API shmget shmat shmdt shmctl 3. 简单的程序 代码实现 common.h shmcreate.c shmrmid.c s ...
- helm笔记
一.注意事项 1.values.yaml 中可以使用'#'号注释行,而/templates 下的文件不能用#号,如果要注释可以使用 {{/* context */}} 2.{{- #忽略 ...
- 1210 BBS admin后台管理及侧边栏筛选个人站点
目录 昨日内容 django admin后台管理 使用 建表 用户图片的显示 MEDIA用户配置 查找照片 搭建个人站点 防盗链 新建css文件 侧边栏展示标签 定义分类栏与标签栏 定义时间栏 侧边栏 ...
- *DataSet序列化,这段代码研究
DataSet序列化,这段代码研究研究.学习学习. using System; using System.Collections.Generic; using System.Linq; using S ...
- easyui-datagrid统计
<script> //打印指定的table function dayin() { var tableToPrint = document.getElementById("dg&q ...