Hibernate hql查询代码实例

本文研究的主要是Hibernate hql查询的相关内容,具体如下。

HQL介绍

Hibernate语言查询(Hibernate Query Language,HQL)它是完全面向对象的查询语句,查询功能非常强大;具备多态、关联等特性,HQL查询也是Hibernate官方推荐使用的查询方法。

下面我们通过一个案例我分析相关查询方法

Classes.java:

public class Classes {
	/*班级ID*/
	private int id;
	/*班级名称*/
	private String name;
	/*班级和学生的关系*/
	private Set<Student> students;
	//省略setter和getter方法
}

Student.java:

public class Student {
	/*学生ID*/
	private int id;
	/*学生姓名*/
	private String name;
	/*学生和班级的关系*/
	private Classes classes;
	//省略setter和getter方法
}

Classes.hbm.xml:

<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC
  "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
  "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<hibernate-mapping package="com.lixue.bean">
  <!-- 设置lazy为false -->
  <class name="Classes" table="t_classes" lazy="false">
    <id name="id">
      <generator class="native"/>
    </id>
    <property name="name"/>
    <!-- 一对多映射 ,inverse="true"表示交给对端维护关系-->
    <set name="students" inverse="true">
       <key column="classesid"/>
      <one-to-many class="Student"/>
    </set>
  </class>
</hibernate-mapping> 

Student.hbm.xml:

<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC
  "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
  "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<hibernate-mapping package="com.lixue.bean">
  <class name="Student" table="t_student">
    <id name="id">
      <generator class="native"/>
    </id>
    <!-- 映射普通属性 -->
    <property name="name"/>
    <!-- 多对一 映射,在多的一端加上外键-->
    <many-to-one name="classes" column="classesid"/>
  </class>
</hibernate-mapping> 

1.查询单一属性:

/*返回结果集属性列表,元素类型和实体类中的属性类型一致*/
      List<String> students = session.createQuery("select name from Student").list();
      /*遍历*/
      for (Iterator<String> iter=students.iterator(); iter.hasNext();) {
        String name = (String)iter.next();
        System.out.println(name);
      } 

注:查询单一属性的时候,返回的是一个集合,集合元素的类型是该属性的类型。

2.查询多个属性,返回对象数组:

/*查询多个属性,返回的是对象数组*/
      List<Object[]> students = session.createQuery("select id, name from Student").list();
      /*遍历*/
      for (Iterator<Object[]> iter=students.iterator(); iter.hasNext();) {
        Object[] obj = (Object[])iter.next();
        System.out.println(obj[0] + ", " + obj[1]);
      } 

注:查询多个属性返回的是一个类型为对象数组的集合,这个很好理解,当查询单一属性是返回的集合元素类型就是属性的类型,但是多个类型呢?那必须是对象数组来处理啊即Object[]。

3.查询多个属性,返回对象类型的集合:

/*我们给实体对象设置对应的构造函数,然后通过查询对象的方式就可以返回一个实体对象类型的集合*/
      List students = session.createQuery("select new Student(id, name) from Student").list();
      /*遍历*/
      for (Iterator iter=students.iterator(); iter.hasNext();) {
        Student student = (Student)iter.next();
        System.out.println(student.getId() + ", " + student.getName());
      } 

注:除了我们第二种方式返回的是一个对象数组,我们还可以给实体对象设置对应的构造函数,然后通过查询对象的方式进行查询,然后返回的就是实体类型的集合。

4.使用别名进行查询:

/*可以使用别名*/
      List<Object[]> students = session.createQuery("select s.id, s.name from Student s").list();
      /*遍历*/
      for (Iterator<Object[]> iter=students.iterator(); iter.hasNext();) {
        Object[] obj = (Object[])iter.next();
        System.out.println(obj[0] + ", " + obj[1]);
      } 

5.查询实体对象:

/*返回的是实体对象类型的集合*/
      List<Student> students = session.createQuery("from Student").list();
      /*遍历*/
      for (Iterator<Student> iter=students.iterator(); iter.hasNext();) {
        Student student = (Student)iter.next();
        System.out.println(student.getName());
      }

注:查询实体可以直接使用from 类名的形式。

/*使用select就必须使用别名*/
      List<Student> students = session.createQuery("select s from Student s").list();
      /*遍历*/
      for (Iterator<Student> iter=students.iterator(); iter.hasNext();) {
        Student student = (Student)iter.next();
        System.out.println(student.getName());
      }

注:如果要使用select关键字,那么就必须使用别名。另外一点千万要注意:hql不支select * 的形式。

6.N+1问题:

/**
       * 采用list查询实体对象会发出一条查询语句,取得实体对象数据
       *
       * Hibernate: select student0_.id as id0_, student0_.name as name0_,
       * student0_.createTime as createTime0_, student0_.classesid as classesid0_
       * from t_student student0_
       */
      List<Student> students = session.createQuery("from Student").list();
      /*遍历*/
      for (Iterator<Student> iter=students.iterator(); iter.hasNext();) {
        Student student = (Student)iter.next();
        System.out.println(student.getName());
      }

注:使用.list()的方式进行对象查询,只会发出一条语句,即取得实体对象数据的语句。

/**
       * 会出现N+1问题,所谓的N+1指的是发出了N+1条sql语句
       *
       * 1:发出一条查询id列表的语句
       * Hibernate: select student0_.id as col_0_0_ from t_student student0_
       *
       * N:根据id发出N条sql语句,加载相关的对象
       * Hibernate: select student0_.id as id0_0_, student0_.name as name0_0_,
       * student0_.createTime as createTime0_0_, student0_.classesid as classesid0_0_
       * from t_student student0_ where student0_.id=?
       *
       */
      Iterator<Student> iter = session.createQuery("from Student").iterate();
      /*遍历*/
      while (iter.hasNext()) {
        Student student = (Student)iter.next();
        System.out.println(student.getName());
      } 

注:通过iterator()方式进行对象查询,会发出N+1条语句,首先会发出一条语句查询出实体对象的ID,然后在根据各自的ID发出N条语句去查询N个对象,这中形式性能是比较差的。

/*通过List查询把查询出的集合存放在一级缓存即session级缓存中*/
      List<Student> students = session.createQuery("from Student").list();
      /*遍历*/
      for (Iterator<Student> iter=students.iterator(); iter.hasNext();) {
        Student student = (Student)iter.next();
        System.out.println(student.getName());
      }
      System.out.println("-----------------------------------------------------");
      /**
       * 避免了N+1问题
       *
       * 因为执行list操作后会将数据放到session的缓存中(一级缓存),所以采用iterate的时候
       * 首先会发出一条查询id列表的语句,再根据id到缓存中加载相应的数据,如果缓存中存在与之匹配的数据
       * 则不再发出根据id查询的sql语句,直接使用缓存中的数据
       *
       * Iterate方法如果缓存中存在数据,它可以提高性能,否则出现N+1问题
       *
       */
      Iterator<Student> iter = session.createQuery("from Student").iterate();
      /*遍历*/
      while (iter.hasNext()) {
        Student student = (Student)iter.next();
        System.out.println(student.getName());
      } 

注:其实Hibernate提供iterator()的方式查询是为了提高性能的,那为什么反而帮了倒忙呢?原因是iterator()是从一级缓存中取数据的,如果缓存中有数据,那么它的效率毫无疑问会相当的给力,但是当我第一次查询的时候缓存中怎么可能会有数据呢,所以就导致了所谓的N+1问题。上面这段代码可以避免N+1问题,它的思路是先用list()进行查询,因为list()查询出来以后,在一级缓存汇总就存在了数据,使用iterator()的时候,效率就会非常的高。

7.条件查询:

/*根据条件进行查询(这里通常都使用别名,比较方便 )*/
      List<Object[]> students = session.createQuery("select s.id, s.name from Student s where s.name like '%0%'").list();
      /*遍历*/
      for (Iterator<Object[]> iter=students.iterator(); iter.hasNext();) {
        Object[] obj = (Object[])iter.next();
        System.out.println(obj[0] + ", " + obj[1]);
      }

注:条件查询和原生的sql相同,都是where关键字。另外通常使用别名比较方便,上述程序是查询多个属性,所以返回的是对象数组类型的集合,对象数组中的元素就是对应的属性。

8.占位符的形式查询:

/*链式编程*/
      List<Object[]> students = session.createQuery("select s.id, s.name from Student s where s.name like ?")
          .setParameter(0, "%0%")
          .list();
      /*遍历*/
      for (Iterator<Object[]> iter=students.iterator(); iter.hasNext();) {
        Object[] obj = (Object[])iter.next();
        System.out.println(obj[0] + ", " + obj[1]);
      } 

注:可以通过占位符的形式进行传参,这种方式可以防止SQL注入。

9.自定义参数的形式:

/*链式编程*/
      List<Object[]> students = session.createQuery("select s.id, s.name from Student s where s.name like :myname")
          .setParameter("myname", "%0%")
          .list();
      /*对象数组*/
      for (Iterator<Object[]> iter=students.iterator(); iter.hasNext();) {
        Object[] obj = (Object[])iter.next();
        System.out.println(obj[0] + ", " + obj[1]);
      } 

注:like :myname冒号后面是没有空格的,否则会出错。

10.查询条件为in的形式:

[java] view plain copy
/*采用in的方式,形参只要一个即可*/
      List<Object[]> students = session.createQuery("select s.id, s.name from Student s where s.id in(:ids)")
          .setParameterList("ids", new Object[]{1, 2, 3, 4, 5})
          .list();
      /*遍历*/
      for (Iterator<Object[]> iter=students.iterator(); iter.hasNext();) {
        Object[] obj = (Object[])iter.next();
        System.out.println(obj[0] + ", " + obj[1]);
      }

注:in后面的括号中只要有一个形参即可,我们设置参数值的时候,可以通过对象数组就行传值。

11.使用数据库个性化函数:

/*查询2009-08的学生,可以调用mysql的日期格式化函数*/
      List<Object[]> students = session.createQuery("select s.id, s.name from Student s where date_format(s.createTime, '%Y-%m')=?")
          .setParameter(0, "2009-08")
          .list();
      /*遍历*/
      for (Iterator<Object[]> iter=students.iterator(); iter.hasNext();) {
        Object[] obj = (Object[])iter.next();
        System.out.println(obj[0] + ", " + obj[1]);
      } 
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
      /*查询2009-08-01 到2009-08-20的学生,可以调用mysql的日期格式化函数*/
      List<Object[]> students = session.createQuery("select s.id, s.name from Student s where s.createTime between ? and ?")
          .setParameter(0, sdf.parse("2009-08-01 00:00:00"))
          .setParameter(1, sdf.parse("2009-08-20 23:59:59"))
          .list();
      /*遍历*/
      for (Iterator<Object[]> iter=students.iterator(); iter.hasNext();) {
        Object[] obj = (Object[])iter.next();
        System.out.println(obj[0] + ", " + obj[1]);
      }

12.使用原生态的SQL语句:

/*使用select * 必须使用原生态的SQL语句,另外它类似于hql查询多个属性,所以返回的是一个对象数组类型的集合*/
      List<Object[]> students = session.createSQLQuery("select * from t_student").list();
      /*遍历*/
      for (Iterator<Object[]> iter = students.iterator(); iter.hasNext();) {
        Object[] obj = (Object[]) iter.next();
        System.out.println(obj[0] + ", " + obj[1]);
      }

注:hql不支持select * 的查询形式,但是Hibernate支持原生态的SQL语句,我们可以利用SQL语句进行查询,另外它类似于HQL的查询多个属性,所以返回的是一个对象数组类型的集合。

13.分页查询

/*分页查询,setFirstResult(1)表示从第一条数据开始查询;setMaxResult(2)表示每页显示2条数据*/
      List students = session.createQuery("from Student")
            .setFirstResult(1)
            .setMaxResults(2)
            .list();
      /*遍历*/
      for (Iterator iter=students.iterator(); iter.hasNext();) {
        Student student = (Student)iter.next();
        System.out.println(student.getName());
      } 

14.导航查询

/*导航查询,s.classes.name从学生导航到班级在导航到班级名称(这是从多的一端导航到少的一端,反过来也可以)*/
      List<Student> students = session.createQuery("from Student s where s.classes.name like '%2%'")
            .list();
      /*遍历*/
      for (Iterator<Student> iter=students.iterator(); iter.hasNext();) {
        Student student = (Student)iter.next();
        System.out.println(student.getName());
      }

注:上述查询语句中的s.classes.name是从学生导航到班级classes在获取班级的名称name。也可以反过来导航:从班级导航到学生在得到某个属性。另外程序中查询语句的意思是要查询班级名称中含有2的所有学生。

15.内连接查询

/*内连接,使用join关键字即可*/
    List<Object[]> students = session.createQuery("select c.name, s.name from Student s join s.classes c")
          .list();
    /*遍历*/
    for (Iterator<Object[]> iter=students.iterator(); iter.hasNext();) {
      Object[] obj = (Object[])iter.next();
      System.out.println(obj[0] + ", " + obj[1]);
    } 

注:内连接关键字为join,另外还是用了别名和导航进行连接。上述查询语句的意思为:从学生表和班级表中查询中班级名称和学生名称(内连接是查询出必须有值得属性,比如没有班级没有学生或者学生没有班级是查询不出来的)。

16.左连接

/*左连接使用关键字left join*/
      List<Object[]> students = session.createQuery("select c.name, s.name from Student s left join s.classes c")
            .list();
      /*遍历*/
      for (Iterator<Object[]> iter=students.iterator(); iter.hasNext();) {
        Object[] obj = (Object[])iter.next();
        System.out.println(obj[0] + ", " + obj[1]);
      }

注:使用左连接的关键字为left join。上述查询语句的意思为:从学生和班级表中,查询出班级名称和学生名称,因为是左连接,所以没有班级的学生也会被查询出来。

17.右连接

[java] view plain copy
/*右连接关键字为right join*/
      List<Object[]> students = session.createQuery("select c.name, s.name from Student s right join s.classes c")
            .list();
      /*遍历*/
      for (Iterator<Object[]> iter=students.iterator(); iter.hasNext();) {
        Object[] obj = (Object[])iter.next();
        System.out.println(obj[0] + ", " + obj[1]);
      }

注:使用右连接的关键字为right join。上述查询语句的意思为:从学生和班级表中,查询出班级名称和学生名称,因为是右连接,所以没有学生的班级会被查询出来。

18.统计查询

Long count = (Long)session.createQuery("select count(*) from Student").uniqueResult();

注:hql中唯有统计查询才可以带*号。uniqueResult()表示只有一条结果集,返回的是Long类型。

19.复合查询

/*查询语句*/
      String hql = "select c.name, count(s) from Classes c join c.students s group by c.name order by c.name"; 

      List<Object[]> students = session.createQuery(hql).list();
      /*遍历*/
      for (int i=0; i<students.size(); i++) {
        Object[] obj = (Object[])students.get(i);
        System.out.println(obj[0] + ", " + obj[1]);
      }

注:hql同样支持分组、排序等等。上述语句的意思是:查询每个班级的名称并且查询出每个班级的学生人数,按班级名称分组,按班级名称排序

总结

以上就是本文关于Hibernate hql查询代码实例的全部内容,希望对大家有所帮助。感兴趣的朋友可以继续参阅本站其他相关专题,如有不足之处,欢迎留言指出。感谢朋友们对本站的支持!

(0)

相关推荐

  • Java Hibernate中使用HQL语句进行数据库查询的要点解析

    一.实体对象查询 实体对象查询是hql查询的基础,作为一种对象查询语言,在查询操作时和sql不同,查询字符串中的内容要使用类名和类的属性名来代替.这种查询方法相对简单,只要有SQL功底,使用hql是很简单的,但是有一些问题需要注意,就是查询获取数据不是目的,需要考虑的是如何编写出高效的查询语句,这才是讨论的重点. 1.N+1问题 (1)什么是N+1问题 在刚听到这个名词时疑惑可能是有的,以前根本就没有听过N+1问题,那么它是指什么呢?N+1指的是一张表中有N条数据,那么在获取这N条数据时会产生N

  • JSP 开发之hibernate的hql查询多对多查询

    JSP 开发之hibernate的hql查询多对多查询 在hibernate的hql查询中,假如说分组信息与试题是多对多关系,那么我们要在hql查询中对含有多个分组信息的试题都要查询出来.并同时查询出相应试题的分组信息.那么此时hql要这样写: String[] groupIds = ojbects[1].toString().split(","); String hql = "SELECT distinct a.id FROM TmEduExamContent a"

  • Hibernate hql查询代码实例

    本文研究的主要是Hibernate hql查询的相关内容,具体如下. HQL介绍 Hibernate语言查询(Hibernate Query Language,HQL)它是完全面向对象的查询语句,查询功能非常强大:具备多态.关联等特性,HQL查询也是Hibernate官方推荐使用的查询方法. 下面我们通过一个案例我分析相关查询方法 Classes.java: public class Classes { /*班级ID*/ private int id; /*班级名称*/ private Stri

  • laravel join关联查询代码实例

    laravel join关联查询 1.两表关联 $fbaInventoryTb = (new \App\Model\Amz\Fba\InventoryReport)->getTable(); $productTb = (new \App\Model\Amz\Product)->getTable(); $twInventoryTb = (new \App\Model\TWUsa\TwusaInventory)->getTable(); $qry = \DB::table($fbaInven

  • 易语言纯IP数据库查询代码实例

    以下是我们给大家分享了易语言IP数据库查询相关的内容代码,大家可以测试下 .版本 2 .支持库 spec .程序集 程序集1 .子程序 _启动子程序, 整数型, , 请在本子程序中放置易模块初始化代码 _临时子程序 () ' 在初始化代码执行完毕后调用测试代码 返回 (0) ' 可以根据您的需要返回任意数值 .子程序 _临时子程序 ' 本名称子程序用作测试程序用,仅在开发及调试环境中有效,编译发布程序前将被系统自动清空,请将所有用作测试的临时代码放在本子程序中. ***注意不要修改本子程序的名称

  • PHP tp5中使用原生sql查询代码实例

    注意事项: 1.先在database.php中配置好数据库 2.只要是数据库操作必须引用 use/think/Db;严格区分大小写. 下面是方法: public function hello5() { //所有查询必须 use/think/Db; /* 1 配置数据库 * 2 使用DB 命名空间 * */ /****************tp5中使用原生语句*******************/ //query 用于查询 其他的用execute // 插入记录 // $result = Db

  • hibernate属性级别注解实例代码

    属性级别注解 添加方式: 写在属性字段上面 写在属性的get访问器的上面 @Id 必须,定义了映射到数据库表的主键的属性,一个实体类可以有一个或者多个属性被映射为主键,可置于主键属性或者getXxx()前,注意:如果有多个属性定义为主键属性,该实体类必须实现serializable接口 @SequenceGenerator @GeneratedValue   @GeneratedValue(strategy=GenerationType,generator=""):可选,用于定义主键生

  • SQL Server 2012 多表连接查询功能实例代码

    废话不多说了,直接给大家贴代码了,具体代码如下所示: -- 交叉连接产生笛卡尔值 (X*Y) SELECT * FROM Student cross Join dbo.ClassInfo --另外一种写法 SELECT * FROM Student , ClassInfo -- 内连接 (Inner 可以省略) SELECT * FROM Student JOIN dbo.ClassInfo ON dbo.Student.Class = dbo.ClassInfo.ID; -- Inner Jo

  • django 按时间范围查询数据库实例代码

    从前台中获得时间范围,在django后台处理request中数据,完成format,按照范围调用函数查询数据库. 介绍一个简单的功能,就是从web表单里获取用户指定的时间范围,然后在数据库中查询此时间范围内的数据. 数据库里的model举例是这样: class book(models.Model): name = models.CharField(max_length=50, unique=True) date = models.DateTimeField() def __unicode__(s

  • hibernate多表操作实例代码

    多表操作之多对多关系简介 思路就是: 在数据库底层通过添加中间表来指定关联关系. 在双方的实体中添加一个保存对方的集合 在双方的配置文件中使用set标签和many-to-many标签来进行关联关系的配置.即可完成! 调用Hibernate的相关的API,操作就行了. 需要注意的地方 首先是数据库中表的创建 这里有一个小例子: 多对多的核心表,第三方表.table: create table thrid( one_id int not null, two_id int not null, cons

  • Spring MVC获取查询参数及路径参数代码实例

    这篇文章主要介绍了Spring MVC获取查询参数及路径参数代码实例,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下 Jsp页面 query.jsp <%@ page contentType="text/html;charset=UTF-8" language="java" %> <%@ page isELIgnored="false" %> <html> &l

随机推荐