Hibernate-ORM:13.Hibernate中的连接查询

本文涉及的产品
云数据库 RDS MySQL Serverless,0.5-2RCU 50GB
简介:     ------------吾亦无他,唯手熟尔,谦卑若愚,好学若饥-------------     本篇博客将会解释Hibernate中的连接查询(各种join) 一,目录   1.

 

 

 

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

 

 

本篇博客将会解释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
        * *//*
    }*/

 

相关实践学习
基于CentOS快速搭建LAMP环境
本教程介绍如何搭建LAMP环境,其中LAMP分别代表Linux、Apache、MySQL和PHP。
全面了解阿里云能为你做什么
阿里云在全球各地部署高效节能的绿色数据中心,利用清洁计算为万物互联的新世界提供源源不断的能源动力,目前开服的区域包括中国(华北、华东、华南、香港)、新加坡、美国(美东、美西)、欧洲、中东、澳大利亚、日本。目前阿里云的产品涵盖弹性计算、数据库、存储与CDN、分析与搜索、云通信、网络、管理与监控、应用服务、互联网中间件、移动服务、视频服务等。通过本课程,来了解阿里云能够为你的业务带来哪些帮助 &nbsp; &nbsp; 相关的阿里云产品:云服务器ECS 云服务器 ECS(Elastic Compute Service)是一种弹性可伸缩的计算服务,助您降低 IT 成本,提升运维效率,使您更专注于核心业务创新。产品详情: https://www.aliyun.com/product/ecs
目录
相关文章
|
XML SQL Java
Hibernate-ORM:14.Hibernate中的命名查询
      ------------吾亦无他,唯手熟尔,谦卑若愚,好学若饥-------------         本篇博客讲述命名查询,所谓命名查询是什么呢? Hibernate中允许我们在xml,实体类,甚至注解的方式来编写查询语句,本篇博客将讲述xml中的方式 一,准备好准备工作,我由于上篇博客把大量的准备都做好,所以,本篇从简 二,预览hbm.
1029 0
|
SQL Java 数据库连接
Hibernate-ORM:15.Hibernate中的Criteria查询
    ------------吾亦无他,唯手熟尔,谦卑若愚,好学若饥-------------         本篇博客讲师Hibernate中的Criteria查询! 一,Criteria简介:   刚接触Hibernate的时候,就有一个概念,全自动的ORM框架,不用写...
980 0
|
SQL 缓存 Java
Hibernate-ORM:16.Hibernate中的二级缓存Ehcache的配置
    ------------吾亦无他,唯手熟尔,谦卑若愚,好学若饥-------------         本篇博客讲述Hibernate中的二级缓存的配置,作者将使用的是ehcache缓存 一,目录   1.
1223 0
|
Java 关系型数据库 数据库连接
Hibernate-ORM:12.Hibernate中的多对多关联关系
    ------------吾亦无他,唯手熟尔,谦卑若愚,好学若饥-------------       本篇博客将讲述Hibernate中的多对多关联关系的操作,准备的篇幅较少,望海涵   一,讲述多对多   多对多的关联关系,比如学生和教师来说,一个学生由多个教师授课...
1244 0
|
安全
Hibernate-ORM:09.Hibernate中的getCurrentSession()
  ------------吾亦无他,唯手熟尔,谦卑若愚,好学若饥-------------         本篇博客将讲述,以优雅的方式创建session对象,我将会说明优点,并提炼成工具类   优点:   1.
1257 0
|
Java 关系型数据库 MySQL
Hibernate-ORM:10.Hibernate中的分页
  ------------吾亦无他,唯手熟尔,谦卑若愚,好学若饥-------------       本篇博客讲述Hibernate中的分页 hibernate中的分页其实很好写,它通过操作对象的方式,来进行分页查询操作 分页无非就是查俩个:1.
938 0
|
Java 关系型数据库 数据库连接
Hibernate-ORM:11.Hibernate中的关联查询
      ------------吾亦无他,唯手熟尔,谦卑若愚,好学若饥-------------         本篇博客将讲述Hibernate中的关联查询,及其级联(cascade)操作,以及指定哪一方维护关联关系的(inverse)   一,讲述目录如下:   1.
1196 0
|
缓存 Java 数据库连接
Hibernate-ORM:06.Hibernate中三种状态
  ------------吾亦无他,唯手熟尔,谦卑若愚,好学若饥-------------       本篇博客主要叙述Hibernate中的三种状态:临时状态(瞬时状态),持久状态,游离状态 commit和flush三种状态间的使用,commit和flush的区别: save...
1096 0
|
SQL Java 数据库连接
Hibernate-ORM:07.Hibernate中的参数绑定
------------吾亦无他,唯手熟尔,谦卑若愚,好学若饥-------------     本篇博客会讲解Hibernate中的参数绑定,就是相当于sql语句中的where后面的条件   一,讲解概述:   1.
1039 0
|
SQL Java 数据库连接
Hibernate-ORM:08.Hibernate中的投影查询
    ------------吾亦无他,唯手熟尔,谦卑若愚,好学若饥-------------       本篇博客将叙述hibernate中的投影查询 一,目录:   1.解释什么是投影查询   2.
1021 0