Hibernate —— HQL、QBC检索方式

一、HQL 检索方式

以双向的一对多来测试 HQL 检索方式。以 Department 和 Employee 为例。

建表语句:

CREATE TABLE department
(
    dept_id INT(11) PRIMARY KEY NOT NULL AUTO_INCREMENT,
    dept_name VARCHAR(50)
);
CREATE INDEX FK_8hf3vewo7w3v9doungcc51wwy ON department (dept_id);
CREATE TABLE employee
(
    emp_id INT(11) PRIMARY KEY NOT NULL AUTO_INCREMENT,
    emp_name VARCHAR(50),
    salary FLOAT,
    dept_id_fk INT(11),
    CONSTRAINT FK_miun1wlqp4ujpsgfshyfi7g9j FOREIGN KEY (dept_id_fk) REFERENCES department (dept_id)
);
CREATE INDEX FK_miun1wlqp4ujpsgfshyfi7g9j ON employee (dept_id_fk);

对应的实体和 hbm 文件

public class Department {
    private Integer deptId;
    private String deptName;
    private Set<Employee> emps = new HashSet<>();
}    
public class Employee {
    private Integer empId;
    private String empName;
    private Float salary;
    private Department dept;
}

<hibernate-mapping>
    <class name="com.solverpeng.hql.Department" table="department" schema="hibernate">
        <id name="deptId" column="dept_id">
            <generator class="native"/>
        </id>
        <property name="deptName" column="dept_name"/>
        <set name="emps" inverse="true">
            <key>
                <column name="dept_id_fk"/>
            </key>
            <one-to-many not-found="ignore" class="com.solverpeng.hql.Employee"/>
        </set>
    </class>
</hibernate-mapping>

Department.hbm.xml

<hibernate-mapping>

    <class name="com.solverpeng.hql.Employee" table="employee" schema="hibernate">
        <id name="empId" column="emp_id">
            <generator class="native"/>
        </id>
        <property name="empName" column="emp_name"/>
        <property name="salary" column="salary"/>
        <many-to-one name="dept" class="com.solverpeng.hql.Department">
            <column name="dept_id_fk"/>
        </many-to-one>
    </class>
    <query name="findAllEmployees">
        <![CDATA[
            from Employee
        ]]>
    </query>
</hibernate-mapping>

Employee.hbm.xml

1.在查询语句中设定各种查询条件

@Test
public void testHql(){
    Department dept = new Department();
    dept.setDeptId(7);

    List<Employee> list = session.createQuery("FROM Employee e where e.empName like ? and e.empId > ? and dept = ? order by e.empId " +
            "desc ")
            .setString(0, "%b%").setInteger(1, 3).setEntity(2, dept).list();

    for(Employee employee : list) {
        System.out.println(employee);
    }

}

说明:

(1)通过 Session 的 createQuery(hql) 方法创建一个 Query 对象,hql 支持动态绑定参数。调用 Query 的相关方法执行查询。

(2)Query 接口支持链式操作,它的 setXxx() 方法返回自身实例。

(3)方法 setEntity(obj),obj 只需要绑定一个 id 就可以。

(4)支持 order by 排序。

(5)参数的位置从 0 开始。

@Test
public void testHqlNamed() {
    List<Employee> list = session.createQuery("from Employee e where e.empName like :name and e.empId > :id and e.dept = ?")
            .setString("name", "%a%").setInteger("id", 1).list();
    for(Employee employee : list) {
        System.out.println(employee);
    }
}

说明:

(1)支持按照参数名字查询,定义的参数名以 ":" 开头。

2.查询对象的部分属性(查询结果仅包含实体的部分属性)

@Test
public void testPropertyQuery() {
    Department dept = new Department();
    dept.setDeptId(7);
    List<Object[]> list = session.createQuery("select empName, empId from Employee where dept = ?").setEntity(0, dept).list();
    for(Object[] objects : list) {
        System.out.println(Arrays.asList(objects));
    }
}

说明:

(1)这种情况下查询出来的是一个 Object[] 数组类型。

@Test
public void testPropertyQuery2() {
    Department dept = new Department();
    dept.setDeptId(7);
    List<Employee> list = session.createQuery("select new Employee (empId, empName) from Employee where dept = ?").setEntity(0, dept)
            .list();
    for(Employee employee : list) {
        System.out.println(employee);
    }
}

(1)查询出来的是 Employee 类型

(2)需要在 Employee 实体类中定义相应的构造器,注意顺序。同时添加一个无参的构造器。

(3)可以通过 Distinct 关键字来去重。

3.分页查询

@Test
public void testHqlPage() {
    int pageNo = 2;
    int pageSize = 3;

    List<Employee> list = session.createQuery("from Employee").setFirstResult((pageNo - 1) * pageSize).setMaxResults(pageSize).list();
    for(Employee employee : list) {
        System.out.println(employee);
    }

}

(1)setFirstResult(int firstResult):设定从哪一个对象开始检索。

(2)setMaxResults(int maxResult) : 设定每次检索多少条记录。

4.命名查询(很少用到)

@Test
public void testNamedQuery() {
    int pageNo = 3;
    int pageSize = 5;
    List<Employee> employees = session.getNamedQuery("findAllEmployees").setFirstResult((pageNo - 1) * pageSize).setMaxResults(
            pageSize).list();
    for(Employee employee : employees) {
        System.out.println(employee);
    }
}

说明:

(1)其中 findAllEmployees 定义在了 Employee.hbm.xml 文件中,用 <query>元素来定义,和 class 节点并列。

(2)通过 Session 的 getNamedQuery() 方法获取对应的 Query 对象。

5.聚集函数和分组查询

@Test
public void testFunction() {
    List<Object[]> salary =
            session.createQuery("select dept.deptName, min(salary), max(salary) from Employee group by dept HAVING min(salary) > :salary")
                    .setFloat("salary", 4000).list();
    for(Object[] objects : salary) {
        System.out.println(Arrays.asList(objects));
    }
}

说明:

(1)通过 GROUP BY 进行分组,通过 HAVING 对分组数据设定约束条件。

(2)可以调用的聚集函数:count() 、min()、max()、sum()、avg()

6.迫切左外链接和左外链接

(1)迫切左外链接

@Test
public void testHqlFetch() {
    List list = session.createQuery("from Department d left join fetch d.emps").list();
}

打印 SQL:

Hibernate:     select        department0_.dept_id as dept1_0_0_,        emps1_.emp_id as emp1_1_1_,        department0_.dept_name as dept2_0_0_,        emps1_.emp_name as emp2_1_1_,        emps1_.salary as salary3_1_1_,        emps1_.dept_id_fk as dept4_1_1_,        emps1_.dept_id_fk as dept4_0_0__,        emps1_.emp_id as emp1_1_0__     from        hibernate.department department0_     left outer join        hibernate.employee emps1_             on department0_.dept_id=emps1_.dept_id_fk

说明:

  • 同时查询了 Employee 对象
  • list() 方法返回的集合存放的实体对象的引用,每个 Department 关联的 Employee 集合都被初始化。
  • 可以通过 distinct 关键字去重,也可以通过一个 HashSet() 去重(new ArrayList<>(new LinkedHashSet(depts)))。
  • 此种情况下,会忽略配置文件中检索策略。

(2)左外链接

@Test
public void testHqlLeftJoin2() {
    List<Object[]> list = session.createQuery("from Department d left join d.emps").list();
    for(Object[] objects : list) {
        System.out.println(Arrays.asList(objects));
    }
}
Hibernate:
    select
        department0_.dept_id as dept1_0_0_,
        emps1_.emp_id as emp1_1_1_,
        department0_.dept_name as dept2_0_0_,
        emps1_.emp_name as emp2_1_1_,
        emps1_.salary as salary3_1_1_,
        emps1_.dept_id_fk as dept4_1_1_
    from
        hibernate.department department0_
    left outer join
        hibernate.employee emps1_
            on department0_.dept_id=emps1_.dept_id_fk

说明:

  • list() 方法返回的集合中存放的是对象数组类型。
  • 根据配置文件来决定 Employee 集合的初始化时机。

7.迫切内连接和内连接

(1)迫切内连接(inner join fetch),与迫切左外链接类似,查询的时候同时将关联的另一端的对象进行了初始化。

(2)内连接(inner join),与左外链接类似,查询的时候是根据配置文件中的检索策略来决定另一端初始化的时机。

8.小结

(1)如果在 HQL 中没有显式的指定检索策略,则使用配置文件中的检索策略。

(2)HQL 会忽略配置文件中设置的迫切左外链接检索策略,若想 HQL 采用迫切左外链接策略,就必须在 HQL 语句中显式的指定它。

二、QBC 检索方式

1.设定各种查询条件

(1)like、gt、排序

@Test
public void testQBC() {
    Criteria criteria = session.createCriteria(Employee.class);

    criteria.add(Restrictions.like("empName", "a", MatchMode.ANYWHERE));
    criteria.add(Restrictions.gt("salary", 1000F));
    // 排序
    criteria.addOrder(Order.desc("salary"));

    List list = criteria.list();
    System.out.println(list);
}
Hibernate:
    select
        this_.emp_id as emp1_1_0_,
        this_.emp_name as emp2_1_0_,
        this_.salary as salary3_1_0_,
        this_.dept_id_fk as dept4_1_0_
    from
        hibernate.employee this_
    where
        this_.emp_name like ?
        and this_.salary>?
    order by
        this_.salary desc

(2)and、or

public void testQbc2() {
    Criteria criteria = session.createCriteria(Employee.class);

    Conjunction conjunction = Restrictions.conjunction();
    conjunction.add(Restrictions.like("empName", "a", MatchMode.ANYWHERE));
    Department department = new Department();
    department.setDeptId(6);
    conjunction.add(Restrictions.eq("dept", department));

    Disjunction disjunction = Restrictions.disjunction();
    disjunction.add(Restrictions.gt("salary", 1000F));
    disjunction.add(Restrictions.lt("salary", 20000F));

    criteria.add(conjunction).add(disjunction);

    criteria.list();

}
Hibernate:
    select
        this_.emp_id as emp1_1_0_,
        this_.emp_name as emp2_1_0_,
        this_.salary as salary3_1_0_,
        this_.dept_id_fk as dept4_1_0_
    from
        hibernate.employee this_
    where
        (
            this_.emp_name like ?
            and this_.dept_id_fk=?
        )
        and (
            this_.salary>?
            or this_.salary<?
        )

2.分页查询

@Test
public void testQbc4() {
    Criteria criteria = session.createCriteria(Employee.class);
    // 分页
    int pageNo = 2;
    int pageSize = 4;
    List<Employee> list = criteria.setFirstResult((pageNo - 1) * pageSize).setMaxResults(pageSize).list();
}
Hibernate:
    select
        this_.emp_id as emp1_1_0_,
        this_.emp_name as emp2_1_0_,
        this_.salary as salary3_1_0_,
        this_.dept_id_fk as dept4_1_0_
    from
        hibernate.employee this_ limit ?,
        ?

3.聚集函数查询

@Test
public void testQbc3() {
    Criteria criteria = session.createCriteria(Employee.class);
    criteria.setProjection(Projections.max("salary"));

    String maxSalary = criteria.uniqueResult().toString();
    System.out.println(maxSalary);
}
Hibernate:
    select
        max(this_.salary) as y0_
    from
        hibernate.employee this

4.小结

(1)创建 QBC 查询:session.createCriteria()

(2)like 关键字:Restrictions.like(),MatchMode.ANYWHERE

(3)排序:criteria.addOrder(),Order.desc、Order.asc

(4)AND:Conjunction conjunction = Restrictions.conjunction()

(5)Or : Disjunction disjunction = Restrictions.disjunction()

(6)聚集函数:criteria.setProjection(Projections.max("salary"))

(7)查询单个对象:criteria.uniqueResult()

(8)查询对象列表:criteria.list()

三、本地 SQL

@Test
public void testNativeSql() {
    Employee employee = new Employee();
    employee.setEmpId(5);
    String empName = (String) session.createSQLQuery("SELECT emp_name FROM employee where emp_id = ?")
            .setEntity(0, employee).uniqueResult();
    System.out.println(empName);
}
Hibernate:
    SELECT
        emp_name
    FROM
        employee
    where
        emp_id = ?
bb2

通过 session.createSQLQuery() 方法来创建本地 SQL 查询对象。

四、HQL 的更新操作

@Test
public void testHqlUpdate() {
    session.createQuery("delete from Employee where empId = ?").setInteger(0, 13).executeUpdate();
}
Hibernate:
    delete
    from
        hibernate.employee
    where
        emp_id=?

五、总结

介绍了 HQL、QBC、本地SQL查询。查询对象都是通过 Session 来创建的。依次为:session.createQuery()、session.createCriteria()、session.createSQLQuery()。

其中 QBC 提供了比 HQL 更为彻底的,更加面向 Java 编程风格的一种方式。在学习 HQL 的时候,需要重点关注迫切左外链接。本地化查询作为对 HQL 的一种补充。

学习的时候,注意对比学习。

更多内容请参看:documentation/manual/en-US/html_single/index.html

时间: 2024-10-16 14:27:49

Hibernate —— HQL、QBC检索方式的相关文章

hibernate检索方式(HQL 检索方式,QBC 检索方式,本地 SQL 检索方式)

hibernate有五种检索方式,这儿用 单向的一对多的映射关系 例子,这儿有后三种的方式: 导航对象图检索方式: 根据已经加载的对象导航到其他对象 OID 检索方式: 按照对象的 OID 来检索对象 HQL 检索方式: 使用面向对象的 HQL 查询语言 QBC 检索方式: 使用 QBC(Query By Criteria) API 来检索对象. 这种 API 封装了基于字符串形式的查询语句, 提供了更加面向对象的查询接口. 本地 SQL 检索方式: 使用本地数据库的 SQL 查询语句 建立封装

Hibernate之QBC检索和本地SQL检索

QBC查询就是通过使用Hibernate提供的Query By Criteria API来查询对象,这种API封装了SQL语句的动态拼装,对查询提供了更加面向对象的功能接口 本地SQL查询来完善HQL不能涵盖所有的查询特性. ====================代码区====================== 测试类 1 package com.yl.hibernate.test; 2 3 4 import java.util.ArrayList; 5 import java.util.A

HQL的检索方式

HQL是面向持久化类的,所以需要查询表的字段都要用持久化类指定例如 String hql = "SELECT e.email, e.salary, e.dept FROM Employee e WHERE e.dept = :dept"; Query query = session.createQuery(hql); 我们要查询表Employees的Email字段,但是我们不能直接select Email from empolyees,而是要通过持久化类来指定 SELECT e.ema

Hibernate之检索方式

时间:2017-1-22 16:09 --检索方式 Hibernate中提供了以下几种检索对象的方式:    *   导航对象图检索方式        根据已经加载额对象导航到其他对象.        >   Customer customer = (Customer)session.get(Customer.class, 1)            customer.getOrders(); // 得到客户的订单 *   OID检索方式        按照对象的OID来检索对象.       

【Hibernate】检索方式

一.概述 二.HQL 2.1 简介 2.2 查询所有记录 2.3 查询使用别名 2.4 排序 2.5 分页查询 2.6 单个对象查询 2.7 参数绑定 2.8 投影操作 2.9 模糊查询 2.10 SQL多表查询 2.11 HQL多表的查询 三.QBC 3.1 简介 3.2 查询所有记录 3.3 排序 3.4分页 3.5获取单个对象 3.6 带参数的查询 3.7 模糊查询 四.SQL 4.1 简介 4.2 SQL语句查询所有记录 一.概述 检索方式:查询的方式 导航对象图检索方式: 根据已经加载

[原创]java WEB学习笔记89:Hibernate学习之路-- -Hibernate检索方式(5种),HQL介绍,实现功能,实现步骤,

本博客的目的:①总结自己的学习过程,相当于学习笔记 ②将自己的经验分享给大家,相互学习,互相交流,不可商用 内容难免出现问题,欢迎指正,交流,探讨,可以留言,也可以通过以下方式联系. 本人互联网技术爱好者,互联网技术发烧友 微博:伊直都在0221 QQ:951226918 -----------------------------------------------------------------------------------------------------------------

Hibernate检索方式-HQL(7)

Hibernate 提供了以下几种检索对象的方式 (1)导航对象图检索方式:  根据已经加载的对象导航到其他对象 (2)OID 检索方式:  按照对象的 OID 来检索对象 (3)HQL 检索方式: 使用面向对象的 HQL 查询语言 (4)QBC 检索方式: 使用 QBC(Query By Criteria) API 来检索对象. 这种 API 封装了基于字符串形式的查询语句, 提供了更加面向对象的查询接口. (5)本地 SQL 检索方式: 使用本地数据库的 SQL 查询语句 HQL(Hiber

Hibernate的检索方式

Hibernate提供以下几种检索对象的方式 1.导航对象图检索方式    根据已经加载的对象,导航到其他对象 2.OID检索方式    按照对象的OID来检索对象 3.HQL检索方式    使用面向对象的HQL查询语言 4.QBC检索方式    使用QBC(Qurey By Criteria) API来检索对象 5.本地SQL检索方式    使用本地数据库的SQL查询语句

Hibernate检索策略与检索方式

hibernate的Session在加载Java对象时,一般都会把鱼这个对象相关联的其他Java对象也都加载到缓存中,以方便程序的调用.但很多情况下,我们不需要加载太多无用的对象到缓存中,一来会占用大量的内存,二来会增加数据库的访问次数,使得程序的运行效率降低.为了合理的使用缓存,Hibernate提供了不同的检索策略来解决这些问题. 作用域 在说检索策略之前,先了解一下检索策略的作用域,它分为:类级别和关联级别.类级别的作用域在检索数据时,检索的数据只包含一个类对象,不涉及与该类关联的其他对象