一、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

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

  1. Hibernate的QBC检索方式

    Hibernate的QBC检索方式 一直习惯了Hibernate的HQL查询,一直也觉得挺方便,对于最近项目里出现的QBC(org.hibernate.Criteria接口)也是报着一种看看的心理,因 ...

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

    hibernate有五种检索方式,这儿用 单向的一对多的映射关系 例子,这儿有后三种的方式: 导航对象图检索方式: 根据已经加载的对象导航到其他对象 OID 检索方式: 按照对象的 OID 来检索对象 ...

  3. Hibernate之QBC检索和本地SQL检索

    QBC查询就是通过使用Hibernate提供的Query By Criteria API来查询对象,这种API封装了SQL语句的动态拼装,对查询提供了更加面向对象的功能接口 本地SQL查询来完善HQL ...

  4. HQL的检索方式

    HQL是面向持久化类的,所以需要查询表的字段都要用持久化类指定例如 String hql = "SELECT e.email, e.salary, e.dept FROM Employee ...

  5. 【Hibernate】检索方式

    一.概述 二.HQL 2.1 简介 2.2 查询所有记录 2.3 查询使用别名 2.4 排序 2.5 分页查询 2.6 单个对象查询 2.7 参数绑定 2.8 投影操作 2.9 模糊查询 2.10 S ...

  6. Hibernate之检索方式

    时间:2017-1-22 16:09 --检索方式Hibernate中提供了以下几种检索对象的方式:    *   导航对象图检索方式        根据已经加载额对象导航到其他对象.        ...

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

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

  8. Hibernate -- 检索方式 HQL

    Hibernate 提供了以下几种检索对象的方式 导航对象图检索方式:  根据已经加载的对象导航到其他对象 OID 检索方式: 按照对象的OID 来检索对象 HQL 检索方式:使用面向对象的HQL查询 ...

  9. Hibernate的检索方式

    Hibernate的检索方式 检索方式(查询的方式) 导航对象图检索方式: 根据已经加载的对象导航到其他对象 Customer customer = (Customer)session.get(Cus ...

随机推荐

  1. LA

    grmon -altjtag -u 公式rand()%(b-a),是求范围随机数的计算公式,%是做求余运算,正整数对n求余的范围肯定是在0~n-1之间,也就是rand()%(b-a)的范围是0~b-a ...

  2. 用jdbc访问大段文本数据

    package it.cast.jdbc; import java.io.BufferedReader; import java.io.BufferedWriter; import java.io.F ...

  3. Key/Value之王Memcached初探:三、Memcached解决Session的分布式存储场景的应用

    一.高可用的Session服务器场景简介 1.1 应用服务器的无状态特性 应用层服务器(这里一般指Web服务器)处理网站应用的业务逻辑,应用的一个最显著的特点是:应用的无状态性. PS:提到无状态特性 ...

  4. iOS开发系列—Objective-C之内存管理

    概述 我们知道在程序运行过程中要创建大量的对象,和其他高级语言类似,在ObjC中对象时存储在堆中的,系统并不会自动释放堆中的内存(注意基本类型是由系统自己管理的,放在栈上).如果一个对象创建并使用后没 ...

  5. 防刷票机制研究和.NET HttpRequest Proxy

    最近应朋友之约 测试他做的投票网站 防刷票机制能力如何,下面有一些心得和体会. 朋友网站用PHP写的,走的是HttpRequest,他一开始认为IP认证应该就差不多了.但说实话这种很low,手动更换代 ...

  6. lua中清空目录和递归创建目录

    lua中的 lfs.mkdir lfs.rmdir只能针对单个目录,且lfs.rmdir不能清空文件夹 于是我想到了使用os.execute 递归创建目录如下os.execute("mkdi ...

  7. [SDK2.2]SQL Azure (13) Azure的两种关系型数据库服务:SQL Azure与SQL Server VM的不同

    <Windows Azure Platform 系列文章目录> 如果熟悉Windows Azure平台的用户不难发现,对于SQL Server数据库来说,微软提供了两种服务,分别是: -W ...

  8. spring快速入门(三)

    一.在spring快速入门(二)的基础上,原先我们是采用构造方法完成对象的注入.这里还有其他的方法可以完成注入,通过set方法来完成. 修改UserActionImpl package com.mur ...

  9. Spring学习记录(七)---表达式语言-SpEL

    SpEL---Spring Expression Language:是一个支持运行时查询和操作对象图表达式语言.使用#{...}作为定界符,为bean属性动态赋值提供了便利. ①对于普通的赋值,用Sp ...

  10. OleDb Source component 用法

    OleDb Source component 主要是从DB中获取数据,传递给下游组件,OleDb Source component的强大之处在于 query data 的mode有四种,如图 Tabl ...