前面我们已经把hibernate中添加"/>

《java从入门到放弃》入门篇:hibernate查询——hql

     2022-03-21     649

关键词:

不知不觉又到了hibernate的最后一篇了,只感觉时光飞逝~,岁月如梭~!

转眼之间,我们就···························,好吧,想装个X,结果装不下去了,还是直接开始吧·技术分享


前面我们已经把hibernate中添加、删改、修改和根据ID得到对象的方法都学习了,但如何才能查询出多条记录呢?比如我想查询所有姓黄的作者,查询标题包含“中”字的博客等。这一篇就来介绍查询。

hibernate有两种检索(查询)数据的方式,分别是HQL(Hibernate Query Language)和QBC(Query By Criteria)。官方推荐使用HQL的方式,不要问我为什么,因为············就算你很诚恳的询问我,我也不会告诉你。反正用过HQL的人都说好。技术分享


HQL提供的语法与SQL非常相似,支持动态参数绑定、投影查询、分页查询、连接查询、分组查询、内置聚集函数、子查询等,可以说是数据库中常用的查询功能,HQL都可以实现。

当然,HQL并不是只能查询,其实也可以用来执行insert、delete和update语句(使用HQL语法),只不过我们今天不讲,大家有兴趣自己练习一下就OK了。


HQL使用步骤:

  1. )获取Session对象

  2. )编写HQL语句

  3. )获得Query对象

  4. )动态绑定参数

  5. )调用执行方法


今天玩点花样,我们通过常用的查询功能来讲解每个语法吧。

一、查询所有的作者

    public static void main(String[] args) {
        Session session = HibernateSessionFactory.getSession();
        //查询所有作者
        String hql = "from Author";
        Query query = session.createQuery(hql);
        List<Author> list = query.list();
        for (Author author : list) {
            System.out.println("姓名:"+author.getUsername());
        }
        HibernateSessionFactory.closeSession();
    }

注意:

1. 查询Author的所有属性时可以省略select部分

2. from后面的Author是Java中的实体类的类名,在HQL语句中 select或from之类的关键字不区别大小写,但类名、属性名必须和实体类大小写完全相同

结果:

技术分享


二、查询作者ID为2的所有博客

    public static void main(String[] args) {
        Session session = HibernateSessionFactory.getSession();
        //查询ID为2的作者的博客
        Author author = (Author)session.get(Author.class, 2);
        //把作者对象当作参数进行查询
        //String hql = "from Blog b where b.author=?";     //占位符方式
        String hql = "from Blog b where b.author=:author";   //参数名方式
        Query query = session.createQuery(hql);
        //添加参数
        //query.setEntity(0, author);      //占位符方式
        query.setEntity("author", author);   //参数名方式
        //执行查询
        List<Blog> list = query.list();
        //遍历结果
        for (Blog blog : list) {
            System.out.println("标题:"+blog.getTitle());
        }
        HibernateSessionFactory.closeSession();
    }

注意:

这儿的条件,where后面的author是Blog实体类中的author属性,参数是什么类型就可以使用setxxx传对应的类型

参数有两种写法:一种是使用“?”,相当于占位符,另一种使用“:xxx”,相当于根据名字传值。

结果:

技术分享


三、查询标题包含“中”字的所有博文

    public static void main(String[] args) {
        Session session = HibernateSessionFactory.getSession();
        //查询标题包含“中”字的所有博文
        String hql = "from Blog b where b.title like ?";
        Query query = session.createQuery(hql);
        //添加参数
        query.setString(0, "%中%");    //参数名方式
        //执行查询
        List<Blog> list = query.list();
        //遍历结果
        for (Blog blog : list) {
            System.out.println("标题:"+blog.getTitle());
        }
        HibernateSessionFactory.closeSession();
    }

注意:

like后面不能写成‘%?%‘,这种写法是错误的。必须在外面拼接好前后的“%”,再作为参数传递给query对象。

结果:

技术分享


四、按博文创建日期倒序排列所有博文

    public static void main(String[] args) {
        Session session = HibernateSessionFactory.getSession();
        //按日期倒序排列所有博文
        String hql = "from Blog b order by b.createTime desc";
        Query query = session.createQuery(hql);
        //执行查询
        List<Blog> list = query.list();
        //遍历结果
        for (Blog blog : list) {
            System.out.println("时间:"+blog.getCreateTime()+",标题:"+blog.getTitle());
        }
        HibernateSessionFactory.closeSession();
    }

注意:

反复看了三遍,发现真的没有哪儿需要注意,我也很绝望啊!技术分享

结果:

技术分享


五、假如每页显示3篇博文,在上一查询的基础上,查询第2页的博文

    public static void main(String[] args) {
        Session session = HibernateSessionFactory.getSession();
        int pageNO = 2;       //页码
        int pageCount = 3;    //每页数量
        //按日期倒序排列所有博文
        String hql = "from Blog b order by b.createTime desc";
        Query query = session.createQuery(hql);
        query.setFirstResult((pageNO-1)*pageCount);        //起始位置
        query.setMaxResults(pageCount);                    //记录数量
        //执行查询
        List<Blog> list = query.list();
        //遍历结果
        for (Blog blog : list) {
            System.out.println("时间:"+blog.getCreateTime()+",标题:"+blog.getTitle());
        }
        HibernateSessionFactory.closeSession();
    }

注意:

setFirstResult表示查询的第一条记录的下标,setMaxResults表示查询几条记录,一般分页都是传递页码(第几页)过来。至于实际项目中的分页如何编写,等后面我们讲常用功能模块时再来说明吧。

结果:

技术分享


六、根据手机号查询作者(确定最多只有一条记录)

    public static void main(String[] args) {
        Session session = HibernateSessionFactory.getSession();
        //查询手机号为13612349876的作者
        String hql = "from Author a where a.phone=?";
        Query query = session.createQuery(hql);
        //添加参数
        query.setString(0, "13612349876");
        //执行查询
        Author author = (Author)query.uniqueResult();
        System.out.println("姓名:"+author.getUsername()+",联系方式:"+author.getPhone());
        HibernateSessionFactory.closeSession();
    }

注意:

确定查询结果最多只有一条记录时,可以使用uniqueResult()方法。

结果:

技术分享



单表查询并且返回所有属性的查询语法,到这儿就告一段落。

接下来进行部分属性的查询、分组查询多表查询子查询



查询语法加上select子句后,返回的结果有以下几种接收方式。

  1. object[]数组

  2. List集合

  3. Map集合

  4. 自定义实体类

我们还是通过例子来学习吧:查询所有博文,只返回标题和内容。

    public static void main(String[] args) {
        Session session = HibernateSessionFactory.getSession();
        //查询所有博文,返回标题和内容
        String hql = "select title,content from Blog";
        Query query = session.createQuery(hql);
        List<Blog> list = query.list();
        for (Blog blog : list) {
            System.out.println("标题:"+blog.getTitle());
            System.out.println("	内容:"+blog.getContent());
        }
    }

运行会发现出现以下异常

技术分享

大概意思就是不能把Object转换成Blog类型

接下来,我们使用上面所说的四种方式来解决这个问题,结果就不再一一展示了。技术分享

1、Object[]数组方式

    public static void main(String[] args) {
        Session session = HibernateSessionFactory.getSession();
        //查询所有博文,返回标题和内容
        String hql = "select title,content from Blog";
        Query query = session.createQuery(hql);
        //执行查询
        List<Object[]> list = query.list();
        for (Object[] objects : list) {
            System.out.println("标题:"+objects[0]);
            System.out.println("	内容:"+objects[1]);
        }
        HibernateSessionFactory.closeSession();
    }

注意:如果只查询一个属性时,返回的就不再在数组,而是单个Object


2、List集合方式

    public static void main(String[] args) {
        Session session = HibernateSessionFactory.getSession();
        //查询所有博文,返回标题和内容
        String hql = "select new List(title,content) from Blog";
        Query query = session.createQuery(hql);
        //执行查询
        List<List> list = query.list();
        for (List lst : list) {
            System.out.println("标题:"+lst.get(0));
            System.out.println("	内容:"+lst.get(1));
        }
        HibernateSessionFactory.closeSession();
    }

注意:HQL语句中的select后面,使用new List()的方式来接受数据。


3、Map集合方式

    public static void main(String[] args) {
        Session session = HibernateSessionFactory.getSession();
        //查询所有博文,返回标题和内容
        String hql = "select new Map(title as t,content as c) from Blog";
        Query query = session.createQuery(hql);
        //执行查询
        List<Map> list = query.list();
        for (Map map : list) {
            System.out.println("标题:"+map.get("t"));
            System.out.println("	内容:"+map.get("c"));
        }
        HibernateSessionFactory.closeSession();
    }

注意:如果new Map()中的属性没有取别名,则在for循环中通过get("下标")的形式来读取数据,特别注意,这儿是字符串"下标",而不是整数。


4、自定义实体类

4.1)在Blog实体类中添加包含标题和内容的构造方法

    //新增构造方法
    public Blog(String title, String content){
        this.title = title;
        this.content = content;
    }

4.2)测试类中的代码

    public static void main(String[] args) {
        Session session = HibernateSessionFactory.getSession();
        //查询所有博文,返回标题和内容
        String hql = "select new Blog(title,content) from Blog";
        Query query = session.createQuery(hql);
        //执行查询
        List<Blog> list = query.list();
        for (Blog blog : list) {
            System.out.println("标题:"+blog.getTitle());
            System.out.println("	内容:"+blog.getContent());
        }
        HibernateSessionFactory.closeSession();
    }

注意:HQL语句中查询几个属性,则在对应的实体类中必须的对应的构造方法

四种方式到这儿就介绍完毕,至于哪种好哪种差,那就看个人习惯了。


继续后面的案例:

七、查询每个作者的博文数量(分组查询)

    public static void main(String[] args) {
        Session session = HibernateSessionFactory.getSession();
        //查询每个作者的博文数
        String hql = "select author, count(b) from Blog b group by b.author";
        Query query = session.createQuery(hql);
        //执行查询
        List<Object[]> list = query.list();
        for (Object[] objects : list) {
            System.out.print("作者:"+((Author)objects[0]).getUsername());
            System.out.println(",博文数:"+objects[1]);
        }
        HibernateSessionFactory.closeSession();
    }

注意:分组之后的统计数据没办法保存到实体类,所以只能使用前三种方式来接受数据。

结果:

技术分享

八、查询所有的博文和作者(作者账号已经注销的不查(也就是博文表中作者ID为null的不查),多表联合查询)

    public static void main(String[] args) {
        Session session = HibernateSessionFactory.getSession();
        //查询所有博文,包括作者信息
        String hql = "from Blog b inner join b.author a";
        Query query = session.createQuery(hql);
        //执行查询
        List<Object[]> list = query.list();
        for (Object[] objs : list) {
            System.out.println("标题:"+((Blog)objs[0]).getTitle());
            System.out.println("	作者:"+((Author)objs[1]).getUsername());
        }
        HibernateSessionFactory.closeSession();
    }

注意:inner join后面的是Blog类中的author属性,Ojbect[]数组中保存的是两个对象。左连接的功能,大家自己尝试吧。

结果:

技术分享


九、最后一个,查询博文数是2的所有作者(子查询)

    public static void main(String[] args) {
        Session session = HibernateSessionFactory.getSession();
        //查询所有博文,包括作者信息
        String hql = "from Author a where (select count(b) from a.blogs b)=2";
        Query query = session.createQuery(hql);
        //执行查询
        List<Author> list = query.list();
        for (Author author : list) {
            System.out.println("作者:"+author.getUsername());
        }
        HibernateSessionFactory.closeSession();
    }

结果:

技术分享

呼~~~~~~技术分享,想不到我也能写出这么长的文章。

破了我30多年来的历史记录啊!!!激动得要技术分享了。

恳请大大给我加个推荐吧~~技术分享


“软件思维”博客地址:51CTO博客园,感兴趣的小伙伴可以去看相关的其它博文。


本文出自 “软件思维” 博客,请务必保留此出处http://softi.blog.51cto.com/13093971/1958271

《java从入门到放弃》入门篇:hibernate中的多表对应关系

hibernate中的对应关系其实就是数据库中表的对应关系,就跟某些电影中的某些场景是一样一样滴。比如可以是一男一女,还可以是一男多女,更可以是多男一女,最后最后最后还可以是多男多女!!!650)this.width=650;"src="https://img... 查看详情

《java从入门到放弃》入门篇:使用注解的方式配置hibernate映射关系

之前我们都是使用配置文件的方式来生成的代码,虽然和JDBC比较简单了很多,但每次都在修改时需要既改实体类又改映射文件。还是有点麻烦。所以,这一篇,我们来说说使用注解的方式来在接在实体类上配置映射关系。第一... 查看详情

《java从入门到放弃》文章目录

...,等相关内容都写完后,再按学习顺序来整理。《Java从入门到放弃》入门篇:XMLHttpRequest的基本用法《Java从入门到放弃》入门篇:Struts2的基本访问方《Java从入门到放弃》入门篇:Struts2的基本访 查看详情

《java从入门到放弃》入门篇:变量

变量是什么玩意呢?变量,顾名思义就是能变化的量--  好吧,举个栗子。图片上的各种餐具,就是变量,因为同一个盘子可以在不同的时间装不同的菜,在这一桌可以装土豆肉丝,在下一桌可以装清炒黄瓜(当然,这个盘... 查看详情

《java从入门到放弃》javase入门篇:集合

今天来讲讲Java中的集合和常见集合类型的使用。什么是集合呢?刚好最近学校里面军训,只听到教官一声喊:“集合!!!”各位小萌新们就屁颠屁颠的跑过来排列整齐了,这就是集合···650)this.width=650;"src="https://img.baidu.com/hi/... 查看详情

《java从入门到放弃》javase入门篇:单元测试

单元测试其实没什么好说的,直接看操作步骤!我们来测试前一篇的小明买食物的方法。第一步:在小明类上点右键,然后再new一个JUnitTestCase650)this.width=650;"src="https://s3.51cto.com/wyfs02/M02/A5/8D/wKioL1m_iAygNbgSAABZDwejGG4076.png"title="11.png"w... 查看详情

《java从入门到放弃》javase入门篇:面向对象语法一(入门版)

前一次简单说明了一下面向对象编程的概念,今天我们就把这些概念通过Java语法来实现,然后看看效果。来看第一个案例:定义女神类,再根据女神类创建三个女神对象,并使用女神对象的属性和方法。第一步:定义女神类(... 查看详情

《java从入门到放弃》入门篇:xmlhttprequest的基本用法

不闲扯,直接开讲。使用XMLHttpRequest对象,主要分为以下七个步骤:创建对象设置过期时间设置数据格式初始化HTTP请求设置HTTP头请求回传数据的处理发送HTTP请求对应代码如下所示<script type="text/javascript">   &nbs... 查看详情

《java从入门到放弃》javase入门篇:网络编程(入门版)

要进行网络编程,首先要搞清楚目的是什么。网络编程说简单点就是在网络上的计算机进行数据的交互。650)this.width=650;"src="https://s4.51cto.com/wyfs02/M00/07/18/wKiom1nDU8jBR29DAADRe0E88II285.png"title="11.png"width="600"height="328"border="0"hspace="0 查看详情

《java从入门到放弃》javase入门篇:面向对象语法二(入门版)

想了半天,发现单独的封装和多态没什么好讲的,我们就简单说说Java里面对应的语法吧。相关内容如下:一、访问修饰符二、getter/setter方法三、构造方法四、super和this五、static关键字六、final关键字七、方法重写八、抽象类和... 查看详情

《java从入门到放弃》javase篇:数组

数组,就是一组数!!!之前我们学习的变量只能保存一个数据,如果一个部门有50个员工的姓名要保存,怎么办?如果定义50个变量··················Stringname1;Stringname2;............Stringname49;Stringname50;,这画面太美,我不... 查看详情

《java从入门到放弃》入门篇:运算符

运算符分为运算和符。运算:是一种行为,通过已知量的可能的组合,获得新的量。 符:上古时期,符是沟通人和神的秘密图案,所以符是不可以随便乱画的,故有所谓“画符不知窍,反惹鬼神笑;画符若知窍,惊得鬼神叫”... 查看详情

《java从入门到放弃》入门篇:运算符

运算符分为运算和符。运算:是一种行为,通过已知量的可能的组合,获得新的量。 符:上古时期,符是沟通人和神的秘密图案,所以符是不可以随便乱画的,故有所谓“画符不知窍,反惹鬼神笑;画符若知窍,惊得鬼神叫”... 查看详情

《java从入门到放弃》javase入门篇:练习——单身狗租赁系统

今天,我们要玩个大的!!!我们把之前使用数组做的这个单身狗系统改版成数据库版本,并且使用面向对象里面的一些简单思想。如果有不知道这个系统的看官,请跳转到目录页,然后再选择单身狗系统(数组版)先围观五分钟... 查看详情

《java从入门到放弃》入门篇:struts2的基本数据传递方式

把这个和JSP的数据传递方式对比一下,你就会发现·······真的可以少写两句代码!!!struts2中常用的两种数据传递方式如下:属性匹配方式ModelDriven接口匹配方式(常用于自定义类型)个人比较喜欢使用第一种,为什么呢?因... 查看详情

《java从入门到放弃》入门篇:struts2的常用验证方式

前一回,我们讲完了“直接在功能方法中写验证代码”这种验证方式,接下来,我们继续搞定后续的三种方式。二、重写validate方法(注意这个方法会验证该类中所有的方法)    使用重写验证方法的好处就是,又... 查看详情

《java从入门到放弃》入门篇:struts2的基本访问方式

Struts2是个什么玩意呢?引用百度百科的介绍:Struts2是一个基于MVC设计模式的Web应用框架,它本质上相当于一个servlet,在MVC设计模式中,Struts2作为控制器(Controller)来建立模型与视图的数据交互。介绍完毕··· 其核心原理图... 查看详情

《java从入门到放弃》入门篇:struts2的基本访问方式

Struts2是个什么玩意呢?引用百度百科的介绍:Struts2是一个基于MVC设计模式的Web应用框架,它本质上相当于一个servlet,在MVC设计模式中,Struts2作为控制器(Controller)来建立模型与视图的数据交互。介绍完毕···其核心原理图网上... 查看详情