------------吾亦无他,唯手熟尔,谦卑若愚,好学若饥-------------

本篇博客将会解释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中的连接查询的更多相关文章

  1. oracle中的连接查询与合并查询总结

    连接查询: 连接查询是指基于多张表或视图的查询.使用连接查询时,应指定有效的查询条件,不然可能会导致生成笛卡尔积.如现有部门表dept,员工表emp,以下查询因查询条件无效,而产生笛卡尔积:   (各 ...

  2. Hibernate批量处理数据、HQL连接查询

    一.批量处理操作 批量处理数据是指在一个事务场景中处理大量数据.在应用程序中难以避免进行批量操作,Hibernate提供了以下方式进行批量处理数据: (1)使用HQL进行批量操作     数据库层面 ...

  3. Hibernate批量处理数据、[HQL连接查询]

    一.批量处理操作 批量处理数据是指在一个事务场景中处理大量数据.在应用程序中难以避免进行批量操作,Hibernate提供了以下方式进行批量处理数据: (1)使用HQL进行批量操作 数据库层面 (2)使 ...

  4. SQL中的连接查询及其优化原则

    连接查询是SQL的主要任务,只有很好的掌握了连接查询及其优化方法才算是掌握了SQL的精髓所在.最近在面试中遇到了有关连接查询的问题,感觉回答的不是很好,总结一下. 具体示例请参考:http://www ...

  5. SQL Server中的连接查询【内连接,左连接,右连接,。。。】

    在查询多个表时,我们经常会用“连接查询”.连接是关系数据库模型的主要特点,也是它区别于其它类型数据库管理系统的一个标志. 什么是连接查询呢? 概念:根据两个表或多个表的列之间的关系,从这些表中查询数据 ...

  6. SQL Server中的连接查询(内连接、外连接、交叉连接)

    在数据库查询中,经常会用到两个有关联的表进行查询,需要把两个表中的数据按照某些条件查出来,这时就可以使用连接查询 连接查询分为三种:内连接.外连接和交叉连接 1. 内连接 内连接inner join ...

  7. MySQL中使用连接查询

    连接查询: 将多张表(可以大于2张)进行记录的连接(按照某个指定的条件进行数据拼接): 最终结果是: 记录数有可能变化, 字段数一定会增加(至少两张表的合并)! 连接查询的意义: 在用户查看数据的时候 ...

  8. SQL 中的连接查询

    关于SQL的应用,肯定离不开查询,而相对复杂的查询,总是离不开对表的连接,单个表操作的并不罕见,但是在应用环境大多数的查询都是针对2.3个表甚至更多的表7,至于连接,有内连接.外链接.交叉连接之分,每 ...

  9. SQL中join连接查询时条件放在on后与where后的区别

    数据库在通过连接两张或多张表来返回记录时,都会生成一张中间的临时表,然后再将这张临时表返回给用户. 在使用left jion时,on和where条件的区别如下: 1. on条件是在生成临时表时使用的条 ...

随机推荐

  1. 【转载】#458 Errors While Converting Between enum and Underlying Type

    You can convert to an enum value from its underlying type by casting the underlying type (e.g. int) ...

  2. 【转】android Looper 理解

    在主线程中运行的部分,都可以直接使用Handler,因为在主线程启动的过程中(ActivityThread的main函数里)会调用Looper.prepareMainLooper(),Looper类中 ...

  3. 问题 A: B 继承 圆到圆柱体

    题目描述 定义了Circle圆形类,在此基础上派生出Cylinder圆柱体类. Circle圆形类定义如下: class Circle { public: Circle(double r):radiu ...

  4. "应用程序无法正常启动(0xc000007b)。请单击 确定 关闭应用程序。"解决方法

    完成一小项目,正常运行,测试环境有Windows XP,Win 7,Win X64及有SP的版本,也是我客户端可能用到的系统版本,Win8和Win10未测试 但在分发过程中,发现有的机器可以正常运行, ...

  5. spring 跨域 CORS (Cross Origin Resources Share) 跨域

    Spring提供了三种方式跨域 1.CorsFilter 过滤器 2.<mvc:cors> Bean(全局,推荐使用) 3.@CrossOrigin注解 以上三种方式本质都是用来配置Cor ...

  6. 学习WebSocket笔记

    由于HTTP协议是无状态的,服务器只会响应来自客户端的请求,但是它与客户端之间不具备持续连接. 当用户在浏览器上进行操作时,可以请求服务器上的api:但是反过来不可以:服务端发生了一件事,无法将这个事 ...

  7. ## `nrm`的安装使用

    作用:提供了一些最常用的NPM包镜像地址,能够让我们快速的切换安装包时候的服务器地址:什么是镜像:原来包刚一开始是只存在于国外的NPM服务器,但是由于网络原因,经常访问不到,这时候,我们可以在国内,创 ...

  8. Showing All Messages : error: open /Users/apple/Library/Developer/Xcode/DerivedData/xxx-dkhmpttmnuppvbcxijlcxacfpzcl/Build/Products/Debug-iphoneos/xxx.app/EaseUIResource.bundle/arrow@2x.png: N

    2报错 Showing All Messages : error: open /Users/apple/Library/Developer/Xcode/DerivedData/xxx-dkhmpttm ...

  9. Sass 基础(八)

    @import Sass 支持所有css 的@规则,以及一些Sass 专属的规则,也被称为“指令(directive)”.这些规则在Sass 中具有不同的 功效,详细解释如下. @import Sas ...

  10. 剑指offer js算法练习(1-10)

    1.二维数组中的查找       在一个二维数组中(每个一维数组的长度相同),每一行都按照从左到右递增的顺序排序,每一列都按照从上到下递增的顺序排序.请完成一个函数,输入这样的一个二维数组和一个整数, ...