Hibernate-ORM:13.Hibernate中的连接查询
------------吾亦无他,唯手熟尔,谦卑若愚,好学若饥-------------
本篇博客将会解释Hibernate中的连接查询(各种join)
一,目录
1.内链接
1.1显式内连接(inner join)
1.1迫切显式内连接(inner join fetch)
2.外连接
2.1左外连接(left join)
2.2迫切左外连接(left join fetch)
2.3以及为什么我们在hibernate中尽量避免使用右外连接,具体的解释
二,准备工作
1.数据库脚本的引用,我把测试需要的数据库的脚本给兄弟们传一下
DROP TABLE IF EXISTS `dept`; CREATE TABLE `dept` (
`deptId` int(11) NOT NULL,
`name` varchar(255) DEFAULT NULL,
`location` varchar(255) DEFAULT NULL,
PRIMARY KEY (`deptId`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8; /*Data for the table `dept` */ insert into `dept`(`deptId`,`name`,`location`) values (1,'xx部','1楼'),(2,'研发部','2楼'),(3,'销售部','3楼'); /*Table structure for table `emp` */ DROP TABLE IF EXISTS `emp`; CREATE TABLE `emp` (
`empId` int(11) NOT NULL,
`name` varchar(255) DEFAULT NULL,
`sal` double DEFAULT NULL,
`job` varchar(255) DEFAULT NULL,
`deptNo` int(11) DEFAULT NULL,
PRIMARY KEY (`empId`),
KEY `FK110A81763AD08` (`deptNo`),
CONSTRAINT `FK110A81763AD08` FOREIGN KEY (`deptNo`) REFERENCES `dept` (`deptId`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8; /*Data for the table `emp` */ insert into `emp`(`empId`,`name`,`sal`,`job`,`deptNo`) values (1,'a',10000,'财务猿1',1),(2,'Ab',5000,'财务猿2',1),(3,'bAa',6000,'财务猿3',1),(4,'aaA',100000,'程序猿1',2),(5,'aB',50000,'程序猿2',2),(6,'AC',60000,'程序猿3',2),(7,'AD',5000000,'Boss',NULL);
连接查询需要使用到的sql脚本
2.实体类的创建:值得注意的是toString()需要做手脚,否者就无限递归了
2.1Dept(部门的实体类)
package cn.dawn.day05.entity; import java.util.HashSet;
import java.util.Set; /**
* Created by Dawn on 2018/6/4.
*/
public class Dept {
private Integer deptId;
private String name;
private String location;
/*一个部门对应多个员工*/
private Set<Emp> emps=new HashSet<Emp>(); public Integer getDeptId() {
return deptId;
} public void setDeptId(Integer deptId) {
this.deptId = deptId;
} public String getName() {
return name;
} public void setName(String name) {
this.name = name;
} public String getLocation() {
return location;
} public void setLocation(String location) {
this.location = location;
} public Set<Emp> getEmps() {
return emps;
} public void setEmps(Set<Emp> emps) {
this.emps = emps;
} @Override
public String toString() {
return "Dept{" +
"deptId=" + deptId +
", name='" + name + '\'' +
", location='" + location + '\'' +
'}';
}
}
2.2Emp(员工实体类)
package cn.dawn.day05.entity; /**
* Created by Dawn on 2018/6/4.
*/
public class Emp {
private Integer empId;
private String name;
private String job;
private Double sal;
//多个员工属于一个部门
private Dept dept; public Integer getEmpId() {
return empId;
} public void setEmpId(Integer empId) {
this.empId = empId;
} public String getName() {
return name;
} public void setName(String name) {
this.name = name;
} public String getJob() {
return job;
} public void setJob(String job) {
this.job = job;
} public Double getSal() {
return sal;
} public void setSal(Double sal) {
this.sal = sal;
} public Dept getDept() {
return dept;
} public void setDept(Dept dept) {
this.dept = dept;
} @Override
public String toString() {
return "Emp{" +
"empId=" + empId +
", name='" + name + '\'' +
", job='" + job + '\'' +
", sal=" + sal +
", dept=" + dept +
'}';
}
}
3.hbm.xml小配置的配置
3.1Dept.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="cn.dawn.day05.entity">
<!--如果上面指定package的话,class的name就不必写全类名-->
<!--lazy:是否懒加载(延迟加载) 默认值是true,延迟加载-->
<!--<class name="Teacher">-->
<!--直接加载-->
<class name="Dept" lazy="false"> <!--主键-->
<id name="deptId" column="deptId">
<!--主键生成策咯 assigned程序员自己创建-->
<!--identity是mysql里的自增,一会做增加操作不必再给主键赋值-->
<!--increment是先查最大的主键列,在下一条给主键加一-->
<!--sequence是oracle的主键生成策咯,他一会需要指定序列名字<param name="sequence">序列名</param>-->
<generator class="assigned"></generator>
</id>
<property name="name"/>
<property name="location"/>
<!--table指的是中间表,承载关联关系的表-->
<set name="emps" cascade="all" inverse="true">
<key>
<!--本类表的id-->
<column name="deptNo"/>
</key>
<!--另外与他有多对多关联的实体类-->
<one-to-many class="Emp"/>
</set>
</class>
</hibernate-mapping>
3.2Emp.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="cn.dawn.day05.entity">
<!--如果上面指定package的话,class的name就不必写全类名-->
<!--lazy:是否懒加载(延迟加载) 默认值是true,延迟加载-->
<!--<class name="Teacher">-->
<!--直接加载-->
<class name="Emp" lazy="false">
<!--主键-->
<id name="empId" column="empId">
<!--主键生成策咯 assigned程序员自己创建-->
<!--identity是mysql里的自增,一会做增加操作不必再给主键赋值-->
<!--increment是先查最大的主键列,在下一条给主键加一-->
<!--sequence是oracle的主键生成策咯,他一会需要指定序列名字<param name="sequence">序列名</param>-->
<generator class="assigned"></generator>
</id>
<property name="name"/>
<property name="sal"/>
<property name="job"/>
<!--table指的是中间表,承载关联关系的表--> <!--另外与他有多对多关联的实体类-->
<many-to-one name="dept" column="deptNo" class="Dept"/>
</class> </hibernate-mapping>
4.hibernate.cfg.xml这个Hibernate核心配置的配置
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE hibernate-configuration PUBLIC
"-//Hibernate/Hibernate Configuration DTD 3.0//EN"
"http://www.hibernate.org/dtd/hibernate-configuration-3.0.dtd">
<hibernate-configuration>
<session-factory>
<!--jdbc连接四要素-->
<property name="hibernate.connection.driver_class">com.mysql.jdbc.Driver</property>
<property name="hibernate.connection.url">jdbc:mysql:///y2167</property>
<property name="hibernate.connection.username">root</property>
<property name="hibernate.connection.password"></property> <!--在控制台上展示sql-->
<property name="show_sql">true</property> <!--格式化sql-->
<!--<property name="format_sql">true</property>--> <!--====================================================================--> <!--ddl操作生成策咯,每次运行都在原有表上修改,没有的话就创建表-->
<!--
<property name="hbm2ddl.auto"></property> key - hbm2ddl.auto:自动生成表结构策略 value - update(使用最多):当数据库不存在表时,hibernate启动后会自动生成表结构。 当数据库表存在时,如果一样,则只会写入数据,不会改变表结构。 当数据库表存在时,如果不一样,则会修改表结构,原有的表结构不会改变。 create(很少):无论表结构是否存在,hibernate启动后都会重新生成表结构。(造成之前的数据丢失) create-drop(极少):无论表结构是否存在,hibernate启动都会重新生成表结构。并且hibernate关闭后,表结构会被删除。来无影去无踪。 validate(很少):不会创建表结构,不会修改表结构。校验与数据库中的表结构是否一样,如果不一样则报异常。
-->
<property name="hbm2ddl.auto">update</property> <!--使用getCurrentSession()需要配置此标签-->
<property name="current_session_context_class">thread</property> <!--与小配置文件映射-->
<mapping resource="cn/dawn/day05/dao/Dept.hbm.xml"></mapping>
<mapping resource="cn/dawn/day05/dao/Emp.hbm.xml"></mapping> </session-factory>
</hibernate-configuration>
三,显式内连接(inner join)
@Test
/*内连接*/
/*返回的是Object[]数组,只有6条数据*/
public void t1innerjoin(){
String hql="from Emp e inner join e.dept";
List<Object[]> list = session.createQuery(hql).list();
for(Object[] o:list){
System.out.println(o[0]);//Emp对象
System.out.println(o[1]);//Dept对象
} /*
Hibernate: alter table Emp add constraint FK42q0wt6tw3e1tcygsbj6pexh foreign key (deptNo) references Dept (deptId)
Hibernate: select emp0_.empId as empId1_1_0_, dept1_.deptId as deptId1_0_1_, emp0_.name as name2_1_0_, emp0_.sal as sal3_1_0_, emp0_.job as job4_1_0_, emp0_.deptNo as deptNo5_1_0_, dept1_.name as name2_0_1_, dept1_.location as location3_0_1_ from Emp emp0_ inner join Dept dept1_ on emp0_.deptNo=dept1_.deptId
Emp{empId=1, name='a', job='财务猿1', sal=10000.0, dept=Dept{deptId=1, name='xx部', location='1楼'}}
Dept{deptId=1, name='xx部', location='1楼'}
Emp{empId=2, name='Ab', job='财务猿2', sal=5000.0, dept=Dept{deptId=1, name='xx部', location='1楼'}}
Dept{deptId=1, name='xx部', location='1楼'}
Emp{empId=3, name='bAa', job='财务猿3', sal=6000.0, dept=Dept{deptId=1, name='xx部', location='1楼'}}
Dept{deptId=1, name='xx部', location='1楼'}
Emp{empId=4, name='aaA', job='程序猿1', sal=100000.0, dept=Dept{deptId=2, name='研发部', location='2楼'}}
Dept{deptId=2, name='研发部', location='2楼'}
Emp{empId=5, name='aB', job='程序猿2', sal=50000.0, dept=Dept{deptId=2, name='研发部', location='2楼'}}
Dept{deptId=2, name='研发部', location='2楼'}
Emp{empId=6, name='AC', job='程序猿3', sal=60000.0, dept=Dept{deptId=2, name='研发部', location='2楼'}}
Dept{deptId=2, name='研发部', location='2楼'}
* */
}
四,迫切显式内连接(inner join fetch)
@Test
/*迫切内连接*/
/*返回的是Object,只有6条数据*/
public void t2innerjoinFetch(){
String hql="from Emp e inner join fetch e.dept";
List<Emp> list = session.createQuery(hql).list();
for(Emp e:list){
System.out.println(e);//Emp对象
} /*
Hibernate: select emp0_.empId as empId1_1_0_, dept1_.deptId as deptId1_0_1_, emp0_.name as name2_1_0_, emp0_.sal as sal3_1_0_, emp0_.job as job4_1_0_, emp0_.deptNo as deptNo5_1_0_, dept1_.name as name2_0_1_, dept1_.location as location3_0_1_ from Emp emp0_ inner join Dept dept1_ on emp0_.deptNo=dept1_.deptId
Emp{empId=1, name='a', job='财务猿1', sal=10000.0, dept=Dept{deptId=1, name='xx部', location='1楼'}}
Emp{empId=2, name='Ab', job='财务猿2', sal=5000.0, dept=Dept{deptId=1, name='xx部', location='1楼'}}
Emp{empId=3, name='bAa', job='财务猿3', sal=6000.0, dept=Dept{deptId=1, name='xx部', location='1楼'}}
Emp{empId=4, name='aaA', job='程序猿1', sal=100000.0, dept=Dept{deptId=2, name='研发部', location='2楼'}}
Emp{empId=5, name='aB', job='程序猿2', sal=50000.0, dept=Dept{deptId=2, name='研发部', location='2楼'}}
Emp{empId=6, name='AC', job='程序猿3', sal=60000.0, dept=Dept{deptId=2, name='研发部', location='2楼'}}
* */
}
五,左外连接(left join)
@Test
/*左外连接*/
/*返回的是Object[]数组,有7条数据,多出来一条,以Emp表为准*/
public void t3leftjoin(){
String hql="from Emp e left join e.dept";
List<Object[]> list = session.createQuery(hql).list();
for(Object[] o:list){
System.out.println(o[0]);//Emp对象
System.out.println(o[1]);//Dept对象
} /*
Hibernate: select emp0_.empId as empId1_1_0_, dept1_.deptId as deptId1_0_1_, emp0_.name as name2_1_0_, emp0_.sal as sal3_1_0_, emp0_.job as job4_1_0_, emp0_.deptNo as deptNo5_1_0_, dept1_.name as name2_0_1_, dept1_.location as location3_0_1_ from Emp emp0_ left outer join Dept dept1_ on emp0_.deptNo=dept1_.deptId
Emp{empId=1, name='a', job='财务猿1', sal=10000.0, dept=Dept{deptId=1, name='xx部', location='1楼'}}
Dept{deptId=1, name='xx部', location='1楼'}
Emp{empId=2, name='Ab', job='财务猿2', sal=5000.0, dept=Dept{deptId=1, name='xx部', location='1楼'}}
Dept{deptId=1, name='xx部', location='1楼'}
Emp{empId=3, name='bAa', job='财务猿3', sal=6000.0, dept=Dept{deptId=1, name='xx部', location='1楼'}}
Dept{deptId=1, name='xx部', location='1楼'}
Emp{empId=4, name='aaA', job='程序猿1', sal=100000.0, dept=Dept{deptId=2, name='研发部', location='2楼'}}
Dept{deptId=2, name='研发部', location='2楼'}
Emp{empId=5, name='aB', job='程序猿2', sal=50000.0, dept=Dept{deptId=2, name='研发部', location='2楼'}}
Dept{deptId=2, name='研发部', location='2楼'}
Emp{empId=6, name='AC', job='程序猿3', sal=60000.0, dept=Dept{deptId=2, name='研发部', location='2楼'}}
Dept{deptId=2, name='研发部', location='2楼'}
Emp{empId=7, name='AD', job='Boss', sal=5000000.0, dept=null}
null
* */
}
六,迫切左外连接(left join fetch)
@Test
/*迫切左外连接*/
/*返回的是Object,有7条数据*/
public void t4leftjoinFetch(){
String hql="from Emp e left join fetch e.dept";
List<Emp> list = session.createQuery(hql).list();
for(Emp e:list){
System.out.println(e);//Emp对象
} /*
Hibernate: select emp0_.empId as empId1_1_0_, dept1_.deptId as deptId1_0_1_, emp0_.name as name2_1_0_, emp0_.sal as sal3_1_0_, emp0_.job as job4_1_0_, emp0_.deptNo as deptNo5_1_0_, dept1_.name as name2_0_1_, dept1_.location as location3_0_1_ from Emp emp0_ left outer join Dept dept1_ on emp0_.deptNo=dept1_.deptId
Emp{empId=1, name='a', job='财务猿1', sal=10000.0, dept=Dept{deptId=1, name='xx部', location='1楼'}}
Emp{empId=2, name='Ab', job='财务猿2', sal=5000.0, dept=Dept{deptId=1, name='xx部', location='1楼'}}
Emp{empId=3, name='bAa', job='财务猿3', sal=6000.0, dept=Dept{deptId=1, name='xx部', location='1楼'}}
Emp{empId=4, name='aaA', job='程序猿1', sal=100000.0, dept=Dept{deptId=2, name='研发部', location='2楼'}}
Emp{empId=5, name='aB', job='程序猿2', sal=50000.0, dept=Dept{deptId=2, name='研发部', location='2楼'}}
Emp{empId=6, name='AC', job='程序猿3', sal=60000.0, dept=Dept{deptId=2, name='研发部', location='2楼'}}
Emp{empId=7, name='AD', job='Boss', sal=5000000.0, dept=null}
* */
}
七,以及为什么我们在hibernate中尽量避免使用右外连接,具体的解释
以右表为准,返回的左表对象,如果右表有一个null值做关联,那么左表的对象就是null,如果把这个对象直接访问其属性,就会引发空指针异常
所以,我们一般不会使用右外连接
@Test
/*迫切右外连接*/
/*返回的是Object,*/
/*hibernate中一般不使用他,不是不能用,而是特别容易出现空指针的异常*/
/*注意观察最后一行查出来的数据,如果我用访问他的属性,这就很难受了*/
/*public void t5rightjoinFetch(){
String hql="from Emp e right join fetch e.dept";
List<Emp> list = session.createQuery(hql).list();
for(Emp e:list){
System.out.println(e);//Emp对象
} *//*
Hibernate: select emp0_.empId as empId1_1_0_, dept1_.deptId as deptId1_0_1_, emp0_.name as name2_1_0_, emp0_.sal as sal3_1_0_, emp0_.job as job4_1_0_, emp0_.deptNo as deptNo5_1_0_, dept1_.name as name2_0_1_, dept1_.location as location3_0_1_ from Emp emp0_ right outer join Dept dept1_ on emp0_.deptNo=dept1_.deptId
Emp{empId=1, name='a', job='财务猿1', sal=10000.0, dept=Dept{deptId=1, name='xx部', location='1楼'}}
Emp{empId=2, name='Ab', job='财务猿2', sal=5000.0, dept=Dept{deptId=1, name='xx部', location='1楼'}}
Emp{empId=3, name='bAa', job='财务猿3', sal=6000.0, dept=Dept{deptId=1, name='xx部', location='1楼'}}
Emp{empId=4, name='aaA', job='程序猿1', sal=100000.0, dept=Dept{deptId=2, name='研发部', location='2楼'}}
Emp{empId=5, name='aB', job='程序猿2', sal=50000.0, dept=Dept{deptId=2, name='研发部', location='2楼'}}
Emp{empId=6, name='AC', job='程序猿3', sal=60000.0, dept=Dept{deptId=2, name='研发部', location='2楼'}}
null
* *//*
}*/
Hibernate-ORM:13.Hibernate中的连接查询的更多相关文章
- oracle中的连接查询与合并查询总结
连接查询: 连接查询是指基于多张表或视图的查询.使用连接查询时,应指定有效的查询条件,不然可能会导致生成笛卡尔积.如现有部门表dept,员工表emp,以下查询因查询条件无效,而产生笛卡尔积: (各 ...
- Hibernate批量处理数据、HQL连接查询
一.批量处理操作 批量处理数据是指在一个事务场景中处理大量数据.在应用程序中难以避免进行批量操作,Hibernate提供了以下方式进行批量处理数据: (1)使用HQL进行批量操作 数据库层面 ...
- Hibernate批量处理数据、[HQL连接查询]
一.批量处理操作 批量处理数据是指在一个事务场景中处理大量数据.在应用程序中难以避免进行批量操作,Hibernate提供了以下方式进行批量处理数据: (1)使用HQL进行批量操作 数据库层面 (2)使 ...
- SQL中的连接查询及其优化原则
连接查询是SQL的主要任务,只有很好的掌握了连接查询及其优化方法才算是掌握了SQL的精髓所在.最近在面试中遇到了有关连接查询的问题,感觉回答的不是很好,总结一下. 具体示例请参考:http://www ...
- SQL Server中的连接查询【内连接,左连接,右连接,。。。】
在查询多个表时,我们经常会用“连接查询”.连接是关系数据库模型的主要特点,也是它区别于其它类型数据库管理系统的一个标志. 什么是连接查询呢? 概念:根据两个表或多个表的列之间的关系,从这些表中查询数据 ...
- SQL Server中的连接查询(内连接、外连接、交叉连接)
在数据库查询中,经常会用到两个有关联的表进行查询,需要把两个表中的数据按照某些条件查出来,这时就可以使用连接查询 连接查询分为三种:内连接.外连接和交叉连接 1. 内连接 内连接inner join ...
- MySQL中使用连接查询
连接查询: 将多张表(可以大于2张)进行记录的连接(按照某个指定的条件进行数据拼接): 最终结果是: 记录数有可能变化, 字段数一定会增加(至少两张表的合并)! 连接查询的意义: 在用户查看数据的时候 ...
- SQL 中的连接查询
关于SQL的应用,肯定离不开查询,而相对复杂的查询,总是离不开对表的连接,单个表操作的并不罕见,但是在应用环境大多数的查询都是针对2.3个表甚至更多的表7,至于连接,有内连接.外链接.交叉连接之分,每 ...
- SQL中join连接查询时条件放在on后与where后的区别
数据库在通过连接两张或多张表来返回记录时,都会生成一张中间的临时表,然后再将这张临时表返回给用户. 在使用left jion时,on和where条件的区别如下: 1. on条件是在生成临时表时使用的条 ...
随机推荐
- php多进程写入文件
测试一 $begin = time(); for ($i=0; $i<10000; $i++) { $fp = fopen("tmp", 'r+'); fseek($fp, ...
- OC 结构体
void test() { // 这个机构只能在函数内部使用 // 定义一个名为Student的结构体类型 struct Student { int age; // 年龄 char *name; // ...
- 每日linux命令之kill
1.命令格式: kill[参数][进程号] 2.命令功能: 发送指定的信号到相应进程.不指定型号将发送SIGTERM(15)终止指定进程.如果任无法终止该程序可用“-KILL” 参数,其发送的信号为S ...
- Android(java)学习笔记19:Java中InetAddress类概述和使用
1. 要想让网络中的计算机能够互相通信,必须为每台计算机指定一个标识号,通过这个标识号来指定要接受数据的计算机和识别发送的计算机. 在TCP/IP协议中,这个标识号就是IP地址. 那么,我们如果获取和 ...
- BZOJ4538:[HNOI2016]网络(树链剖分,堆)
Description 一个简单的网络系统可以被描述成一棵无根树.每个节点为一个服务器.连接服务器与服务器的数据线则看做 一条树边.两个服务器进行数据的交互时,数据会经过连接这两个服务器的路径上的所有 ...
- HDU 5723 最小生成树上的期望
题意:求最小生成树,和任意两个点之间距离的期望 官方题解: 最后求两遍点的积的时候,还是要判断父子关系. 注意 long long #include <bits/stdc++.h> usi ...
- EF Ccore 主从配置 最简化
业务需要 配置一主多从数据库 读写分离 orm用的ef core , 把思路和代码写下 1. 配置2个数据库上下文 ETMasterContext ETSlaveContext(把增删改功能禁用掉 ...
- C# DataSet.Designer.cs
今天在做项目的时候,发现一个很奇葩的问题,VS 中DataSet数据集的问题Dataset数据集更新,在保存后原有的Dataset.Designer.cs不变,又增加一个新的Dataset1.Desi ...
- 【洛谷P2447】[SDOI2010]外星千足虫
外星千足虫 题目链接 首先,它一看题解就是个高斯消元 只是改成了奇偶性的判断 性质: 奇数+奇数=偶数 奇数+偶数=奇数 偶数+奇数=奇数 偶数+偶数=偶数 于是我们用1表示奇数,0表示偶数 1+1= ...
- 【luogu P3375 KMP字符串匹配】 模板
题目链接:https://www.luogu.org/problemnew/show/P3375 精华:在每次失配后不从头匹配而是尝试找一个新的开始并且是新开始的位置最长的相同前缀和后缀. 实际上KM ...