Hibernate-02 HQL实用技术
学习任务
- Query接口的使用
 - HQL基本用法
 - 动态参数绑定查询
 
HQL的使用
Hibernate支持三种查询方式:HQL查询、Criateria查询、Native SQL查询。
HQL是Hibernate查询语言(Hibernate Query Language),是一种面向对象的查询语言, 其中没有表和字段的概念,只有类、对象和属性的概念。
HQL语句编写
HQL语句除了Java类和属性的名称外,对大小写不敏感。在实际使用中通常对HQL中的关键字使用小写字母。
1.from
# 查询所有部门
from com.etc.entity.Dept --部门全限定类名
from Dept --省略了包名
from Dept as dept --使用as指定Dept的别名为dept
from Dept dept --指定别名as可选
2.select
select子句用于选择对象和属性。
# 查询部门名称
select dept.deptName from Dept as dept
# 使用部门别名
select dept from Dept as dept
3.where
where字句用于构造查询条件。
# 查询部门名称是SALES的部门对象
from Dept where deptName = 'SALES'
# 使用指派的别名查询
from Dept as dept where dept.deptName = 'SALES'
# 查询部门地址不为NULL的部门对象
from Dept dept where dept.location is not null
4.表达式的使用
表达式一般用在where子句中。以下两个HQL语句在where子句中分别使用了lower()函数和year()函数。
# 查询部门名称是sales的部门对象,不区分大小写
from Dept dept where lower(dept.deptName) = 'sales'
# 查询2016年入职的员工
from Emp where year(hireDate) = 2016
5.Order by
用于按照指定属性排序。
# 查询所有员工,按照入职时间升序排序
from Emp order by hireDate asc
# 查询所有员工,按照入职时间升序排序。如果入职时间相同,则按照工资降序排序。
from Emp order by hireDate, salary desc
执行HQL语句
步骤
- 获取Session对象
 - 编写HQL语句
 - 创建Query对象
 - 执行查询,得到查询结果
 
list()方法执行HQL
1.DAO关键代码
session = sessionFactory.getCurrentSession();
String hql = "from Emp";
Query query = session.createQuery( hql );
List<Emp> empList = query.list();
2.BIZ关键代码
/** list方法查询全部信息 */
public List<Emp> listEmps() {
Transaction tx = null;
List<Emp> list = null;
try {
tx = empDao.getSession().beginTransaction();
list = empDao.listEmp();
tx.commit();
} catch (Exception e) {
e.printStackTrace();
if (tx != null) {
tx.rollback();
}
}
return list;
}
3.测试方法关键代码
	public void testList() {
		List<Emp> list = new EmpBiz().listEmps();
		System.out.println("\n===员工信息集合===");
		for (Emp item : list) {
			System.out.println(item.getEmpNo() + "\t" + item.getEmpName());
		}
	}
4.Hibernate生成SQL语句
Hibernate:
select
emp0_."EMPNO" as EMPNO1_1_,
emp0_."ENAME" as ENAME2_1_,
emp0_."JOB" as JOB3_1_,
emp0_."MGR" as MGR4_1_,
emp0_."HIREDATE" as HIREDATE5_1_,
emp0_."SAL" as SAL6_1_,
emp0_."COMM" as COMM7_1_,
emp0_."DEPTNO" as DEPTNO8_1_
from
scott."EMP" emp0_
iterate()方法执行HQL
1.DAO关键代码
session = sessionFactory.getCurrentSession();
String hql = "from Emp";
Query query = session.createQuery( hql );
Iterator<Emp> empIterator = query.iterate();
2.BIZ关键代码
/** iterator方法查询全部信息 */
public Iterator<Emp> iteratorEmps() {
Transaction tx = null;
Iterator<Emp> it = null;
try {
tx = empDao.getSession().beginTransaction();
// 遍历输出结果,与list方法不同的地方在于需要在一个会话结束前输出查询结果
it = empDao.iteratorEmp();
Emp item = null;
System.out.println("\n===员工信息集合===");
while (it.hasNext()) {
item = it.next();
System.out.println(item.getEmpNo() + "\t" + item.getEmpName());
}
tx.commit();
} catch (Exception e) {
e.printStackTrace();
if (tx != null) {
tx.rollback();
}
}
return it;
}
3.测试方法关键代码
	public void testIterator() {
		new EmpBiz().iteratorEmps();
	}
4.Hibernate生成SQL语句
先查询全部员工OID信息集合
Hibernate:
select
emp0_."EMPNO" as col_0_0_
from
scott."EMP" emp0_
需要获取员工其他信息的时候再根据OID对数据库二次查询
# 执行多条如下SQL语句
Hibernate:
select
emp0_."EMPNO" as EMPNO1_1_0_,
emp0_."ENAME" as ENAME2_1_0_,
emp0_."JOB" as JOB3_1_0_,
emp0_."MGR" as MGR4_1_0_,
emp0_."HIREDATE" as HIREDATE5_1_0_,
emp0_."SAL" as SAL6_1_0_,
emp0_."COMM" as COMM7_1_0_,
emp0_."DEPTNO" as DEPTNO8_1_0_
from
scott."EMP" emp0_
where
emp0_."EMPNO"=?
list()方法和iterator()方法的区别
- 从Hibernate生成的SQL语句可以看出,list()方法生成一条SQL查询语句,查询所有符合条件的记录。
 - iterate()方法首先查询出所有符合条件的主键值,此处是empno,然后在需要某一对象的其他属性值时,オ生成按主键查询的SQL语句。即iterate()方法可能生成1+N条SQL语句(N为第一条语句获取的EMP对象的数量)。
 
HQL参数绑定
使用字符串拼接查询条件存在各种弊端
例如HQL语句:
"from User where name = '" + name + "'"
存在问题:
- 从性能方面,Hibernate底层使用JDBC的PreparedStatement对象访问数据库。如果直接将属性值写在语句中,那么每次执行SQL语句, 数据库都会重新编译SQL语句,从而导致性能降低。
 - 从安全角度,这种字符串的拼装造成的漏洞是SQL注入攻击的主要目标。
 - 在实际开发中,不使用字符串拼接的方式来构建HQL语句,而使用参数绑定的方式。
 
参数绑定的形式
参数绑定的两种形式
- 按参数位置绑定(下标从0开始)
 
from User where name = ?
- 按参数名称绑定(可读性好,易维护,推荐使用)
 
from User where name = :name
示例代码
//查询参数的绑定方式
/**按照参数位置绑定参数:根据部门名称查询部门*/
public List<Dept> findByDeptName(String deptName){
String hql="from Dept as dept where dept.deptName=?";
Query query=this.getSession().createQuery(hql);
query.setString(0, deptName);//位置从0开始计算
return query.list();
} /**按照参数名称绑定参数:根据部门名称查询部门*/
public List<Dept> findByDeptName2(String deptName){
String hql="from Dept as dept where dept.deptName=:name";
Query query=this.getSession().createQuery(hql);
query.setString("name", deptName);//位置从0开始计算
return query.list();
}
绑定各种类型参数
1.为任意参数类型赋值
query接口提供了setXXX()重载方法针对具体数据类型进行赋值(XXX表示各种数据类型):
setXXX(int position, XXX value);//按照位置传参赋值
setXXX(String name, XXX value);//按照参数名称传参赋值
Hibernate提供setParameter()用来绑定任意类型参数。
setParameter( int position, Object value);//按照位置为参数赋值
setParameter( String name, Object value);//按照参数名为参数赋值
示例代码
/** 使用setParameter()绑定各种类型参数 */
public List<Emp> findByConditions(Object[] conditions) {
// 查询依赖多个条件,且类型各异
String hql = "from Emp where job=? and sal>?";
Query query = this.getSession().createQuery(hql);
if (conditions != null && conditions.length > 0) {
for (int i = 0; i < conditions.length; ++i) {
query.setParameter(i, conditions[i]);//为占位符赋值
}
}
return query.list();
}
2.setProperties()方法:绑定命名参数与一个对象的属性值
setProperties()方法即可根据参数名获取对象中的相关属性值完成赋值。
示例代码
/** 使用setProperties()方法绑定命名参数和一个对象属性值 */
public List<Emp> findByConditions2(Emp conditions) {
// 查询依赖多个条件,且类型各异
String hql = "from Emp where job=:job and sal>:sal";
Query query = this.getSession().createQuery(hql);
// 根据命名参数的名称,从conditions对象中相同名称属性上取值
query.setProperties(conditions);
return query.list();
}
3.NULL
参数绑定对NULL是安全的,生成的SQL语句条件将是“==null”。
但如果希望查询到NULL值条件数据。使用IS NULL构造查询条件查询。
实现动态查询
在査询条件很多的情况下,传递过多的参数很不方便。此时,可以把参数封装在对象中,再使用之前所述的Query接口的setProperties()方法为HQL中的命名参数赋值。setProperties()方法会把对象的属性匹配到命名参数上,需注意命名参数名称要与Java对象的属性匹配。
需要解决的问题
查找出符合以下条件的员工信息
- 职位是店员,如:job = 'CLERK'
 - 工资大于1000元,如:sal > 1000
 - 入职时间在1981年4月1日至1985年9月9日之间
 
问题分析
- 条件个数不确定
 - 最多有三个
 - 需要动态设置查询条件
 
解决方案示例代码
1.查询条件信息封装类
package com.etc.entity; import java.util.Date; /** 封装员工信息查询条件的实体类 */
public class EmpCondition {
private String job;// 职位
private Double sal;// 工资
private Date hireDateEnd;// 员工入职结束时间
private Date hireDateStart;// 员工入职开始时间
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 Date getHireDateEnd() {
return hireDateEnd;
}
public void setHireDateEnd(Date hireDateEnd) {
this.hireDateEnd = hireDateEnd;
}
public Date getHireDateStart() {
return hireDateStart;
}
public void setHireDateStart(Date hireDateStart) {
this.hireDateStart = hireDateStart;
} }
2.日期类型转换工具类
public class Tool {
	/**日期指定格式日期字符串转换为日期对象*/
	public static Date strToDate(String dateStr, String pattern) {
		try {
			return new SimpleDateFormat(pattern).parse(dateStr);
		} catch (Exception e) {
			e.printStackTrace();
			return null;
		}
	}
}
3.DAO关键代码
/** 使用setProperties()实现动态查询 */
public List<Emp> findByConditions3(String hql, EmpCondition conditions) {
Query query = this.getSession().createQuery(hql);
// 根据命名参数的名称,从conditions对象中相同名称属性上取值
query.setProperties(conditions);
return query.list();
}
4.BIZ关键代码
/** 使用setProperties()实现动态查询 */
public List<Emp> findEmpsByConditions3(EmpCondition conditions) {
Transaction tx = null;
List<Emp> emps = null;
try {
tx = empDao.getSession().beginTransaction();
// 动态生成HQL
StringBuilder hql = new StringBuilder("from Emp as emp where 1=1");
if (conditions.getJob() != null && conditions.getJob().length() > 0) {
hql.append(" and emp.job=:job");
}
if (conditions.getSal() != null && conditions.getSal() != 0) {
hql.append(" and emp.sal>:sal");
}
if (null != conditions.getHireDateStart()) {
hql.append(" and emp.hireDate>:hireDateStart");
}
if (null != conditions.getHireDateEnd()) {
hql.append(" and emp.hireDate<:hireDateEnd");
}
emps = empDao.findByConditions3(hql.toString(), conditions);
tx.commit();
} catch (HibernateException e) {
e.printStackTrace();
if (tx != null) {
tx.rollback();
}
}
return emps;
}
唯一结果查询
query接口的uniqueResult()可以用于查询唯一结果。
示例代码
1.DAO关键代码
/** 使用uniqueResult()方法获得唯一结果 */
public Long obtainTheRowCount(Double sal) {
String hql = "select count(id) from Emp where sal >= :sal";// count中的id为对象oid,也可以使用emp属性empNo
return (Long) this.getSession().createQuery(hql).setDouble("sal", sal)
.uniqueResult(); }
2.BIZ关键代码
/** 使用uniqueResult()方法获得唯一结果 */
public Long countBySal(Double sal) {
Transaction tx = null;
Long result = null;
try {
tx = empDao.getSession().beginTransaction();
result = empDao.obtainTheRowCount(sal);
tx.commit();
} catch (HibernateException e) {
e.printStackTrace();
if (tx != null) {
tx.rollback();
}
}
return result;
}
注意:当查询结果不唯一的情况下,uniqueResult()会报错。
分页和投影
分页查询
使用到的函数
- uniqueResult() :获取唯一对象。结合count()函数获取记录数。
 - setFirstResult() :设置从第几条开始
 - setMaxResults():设置读取最大记录数
 
分页步骤
1.使用count函数获得总记录数
2.计算总页数
int totalpages = (count%pageSize == 0 ) ? (count / pageSize) : (count / pageSize + 1);
3.实现分页查询
int pageIndex = 2;
int pageSize = 2;
List<Emp> empList=new EmpBiz().findEmpsByPage(pageIndex, pageSize);
for(Emp item:empList){
System.out.println("员工编号为:"+item.getEmpNo()+"\t"+item.getEmpName());
}
示例代码:(员工信息分页查询为例)
1.DAO关键代码
/** 分页查询 */
public List<Emp> findByPage(int pageIndex, int pageSize) {
return this.getSession().createQuery("from Emp order by id")
.setFirstResult((pageIndex - 1) * pageSize)
.setMaxResults(pageSize).list();
}
2.BIZ关键代码
/** 分页查询 */
public List<Emp> findEmpsByPage(int pageIndex, int pageSize) {
Transaction tx = null;
List<Emp> empList = null;
try {
tx = empDao.getSession().beginTransaction();
empList = empDao.findByPage(pageIndex, pageSize);
tx.commit();
} catch (HibernateException e) {
e.printStackTrace();
if (tx != null) {
tx.rollback();
}
}
return empList;
}
投影查询
HQL投影查询是查询一个持久化类的一个或多个属性值,或者是通过表达式或聚合函数得到的值。
投影查询需要使用HQL的select子句,查询结果的封装主要分三种情况:
- 封装成Object对象
 - 封装成Object数组
 - 通过构造方法封装成对象。(对象不是持久化状态,仅用于封装结果)
 
若查询结果仅用于展示,不需要保持持久化状态,应尽量使用投影查询以减少开销,提高效率。
示例代码
//投影查询
/**获得部门名称集合:只查询一个属性*/
public List<String> findaAllNames(){
String hql="select deptName from Dept";
Query query=this.getSession().createQuery(hql);
return query.list();
} /**查询部门编号和部门名称:通过数组接收多个属性*/
public List<Object[]> findDeptList(){
String hql="select deptNo,deptName from Dept";
Query query=this.getSession().createQuery(hql);
return query.list();
} /**查询部门编号和部门名称:通过构造函数接收多个属性*/
public List<Dept> findDeptList2(){
String hql="select new Dept(deptNo,deptName) from Dept";//dept队形只用于封装,非持久化状态
Query query=this.getSession().createQuery(hql);
return query.list();
}
Hibernate-02 HQL实用技术的更多相关文章
- 第五章   HQL实用技术
		
第五章 HQL实用技术5.1 使用HQL查询语句(面向对象查询语句) 5.1.1 编写HQL语句 5.1.1.1 from子句 例:fr ...
 - hibernate的hql查询
		
1.概念介绍 1.Query是Hibernate的查询接口,用于从数据存储源查询对象及控制执行查询的过程,Query包装了一个HQL查询语句. 2.HQL是Hibernate Query Langua ...
 - Hibernate学习-Hibernate查询语言HQL
		
HQL(Hibernate Query Language)Hibernate查询语言,语法类似于SQL,可以直接使用实体类及属性. 使用HQL 可以避免使用JDBC 查询的一些弊端 不需要再编写繁复的 ...
 - Hibernate之HQL查询
		
一.Hibernate 提供了以下几种检索对象的方式: 导航对象图检索方式: 根据已经加载的对象导航到其他对象 OID 检索方式: 按照对象的 OID 来检索对象 HQL 检索方式:使用面向对象的 H ...
 - Hibernate之HQL介绍
		
Hibernate中提供了多种检索对象的方式,主要包括以下种类: 导航对象图检索方式:根据已经加载的对象导航到其他对象 OID检索方式:根据对象的OID来检索对象 HQL检索方式:使用面向对象的HQL ...
 - Hibernate五 HQL查询
		
HQL查询一 介绍1.HQL:Hibernate Query Language,是一种完全面向对象的查询语言.使用Hibernate有多重查询方式可供选择:hibernate的HQL查询,也可以使用条 ...
 - Hibernate 的hql查询简介【申明:来源于网络】
		
Hibernate 的hql查询简介[申明:来源于网络] Hibernate 的hql查询简介:http://blog.csdn.net/leaf_130/article/details/539329 ...
 - Hibernate的hql语句save,update方法不执行
		
Hibernate的hql语句save,update方法不执行 可能出现的原因问题: 未进行事务管理 需要进行xml事务配置或者注解方式的事务配置
 - Hibernate学习---第九节:Hibernate之hql
		
一.Hql 入门 1.实体类: package learn.hibernate.bean; import java.util.Date; import java.util.HashSet; impor ...
 - Java_Web三大框架之Hibernate+jsp+HQL分页查询
		
分页查询无处不在.使用Hibernate+jsp+HQL进行分页查询. 第一步:编写房屋实体类和House.hbm.xml映射. /* * 房屋实体类 */ public class House { ...
 
随机推荐
- mysql5.7 异常ERROR 1055 (42000)
			
大致错误如:ERROR 1055 (42000): Expression #1 of SELECT list is not in GROUP BY clause and contains nonagg ...
 - 【转】PL/SQL 使用技巧
			
ref:http://blog.chinaunix.net/uid-21592001-id-3082675.html [转]plsql developer 使用技巧 Oracle数据库相信已成为很多企 ...
 - 爱奇艺面试Python,竟然挂在第5轮……
			
今天给大家分享我曾经在爱奇艺的面试,过程还是比较有意思的,可以给大家一些参考 聊骚阶段 嗲妹妹:你好,我是爱奇艺的HR,我们正在招聘运维开发岗位,请问您最近有在看工作机会吗? 我:(这声音也太酥了吧我 ...
 - 一个坑爹的Swift报错原因分析与解决方案
			
有时候在实际开发中,完全没有任何问题.但是一到实机测试,就会直接卡机 let count = scoreStorage.count return scoreStorage[Int(arc4rand ...
 - ErrorObject OpenAsync(Action<ErrorObject>arg_fnRet)
			
ErrorObject OpenAsync(Action<ErrorObject>arg_fnRet) public static ErrorObject Open(this ReadWr ...
 - Mac下怎么运行python3的py文件
			
我的Mac现在是10.14.6系统,默认自带的python版本是2.7.(怎么查看版本?打开终端,输入python即可看到版本号) 由于现在需要运行python3写的py文件,需要将自带的python ...
 - C++ 的输出格式
			
0 在C语言中很简单对输出的要求,然而在C++中有一丝的麻烦. 在下面的代码中所需要的是 #include<iostream> 基本输入/输出库 #include<iomanip&g ...
 - Hexo搭建博客教程(3) - 远程部署到GitHub Pages
			
本章讲的是如何将本地的个人项目远程部署到 GitHub Pages,涉及到GitHub的项目仓库.Git的使用,以及Hexo的远程部署等. 1. 安装 hexo-deployer-git 插件 想要将 ...
 - Java | 技术应用 | 利用Jsoup处理页面
			
根据微信公众号的推文链接地址,对文章内容进行爬取,利用jsoup解析文章源代码,加上结合xpth提取文文章信息, 利用正则表达式读取文章发表时间. Jsoup <!-- jsoup HTML p ...
 - AtCoder Grand Contest 005 C - Tree Restoring
			
题目传送门:https://agc005.contest.atcoder.jp/tasks/agc005_c 题目大意: 给定一个长度为\(N\)的整数序列\(A_i\),问能否构造一个\(N\)个节 ...