12.1 HQL语言基础
Hibernate查询语言为HQL(Hibernate Query Language),可以直接使用实体类名及属性。HQL语法类似于SQL,有SQL的关键词如select、from、order by、count()、where等等。不同的是HQL是一种完全面向对象的语言,能够直接查询实体类及属性。
12.1.1 HQL语法
HQL语法类似于SQL,是一种select...from...的结构。其中,from后跟的是实体类名,而不是表名。select后面跟的可以是实体对象,也可以使实体对象的属性或者其他值,例如:
Query query = session.createQuery(" select * from Users as users ");// 查询所有的Users
List list = query.list(); // 执行查询,返回List
其中,Users为实体类Users,users为Users对象,关键词as用法同SQL,可以省略。Query是Hibernate的查询对象,query.list()将以List类型返回查询结果。上述查询也可以简写为:
Query query = session.createQuery(" from Users "); // 查询所有的Users
List list = query.list(); // 执行查询,返回List
12.1.2 HQL中的大小写
HQL语言大小写不敏感,“select * from Users as users”也可写作“SELECT * FROM Users as users”。但是涉及到Java类名、package名、属性名时,需要区分大小写,因此Users必须与类名一致。
12.1.3 查询中使用包名
一个工程中,如果不存在相同的实体类名,查询语句中实体类所在的package可省略。Hibernate会能够根据类名检索到实际的t实体类。但如果有相同的实体类名,查询时必须携带package信息,否则Hibernate不知道使用哪一个实体类。使用包名的查询语句实例代码如下:
SELECT users FROM com..java.vo.Users users
12.1.4 查询结果的返回类型
Hibernate使用Query对象进行查询。Session的createQuery方法能够创建Query实例,参数为HQL。Query对象能够返回各种类型的查询结果,例如long、String、List<</font>实体类名>、List、POJO等。最常用的查询方法有uniqueResult()与list()等。其中uniqueResult()返回单个值,而list()返回零个或者多个值。下面分别介绍uniqueResult()与list()。
1. uniqueResult()返回单个值
Query的unique()返回单个的对象。使用unique()获取返回值时,HQL语句查询到的结果最多只能有一个,如果结果多于一个,unique()方法会抛出异常。如果没有,会返回null。这个方法常常用来查询记录总数,因为总会返回一个对象,并且也只有一个。例如:
Query q = session.createQuery(" select count(*) from Users "); // 创建查询对象
Number num = (Number)q.uniqueResult(); // 返回单个实例
int count = num.intValue(); // 返回数值
查询总数时,HQL格式必须为“select count(*) from Users”的格式。返回值可能为Short、Integer、Long、BigInteger等各种类型,具体返回类型根据主键的类型而定。这里可以用所有数值类型的父类Number类型。
2. list()返回集合
Query的list()方法是最常用的方法。实际上,unique()方法也是在list()方法得到返回数据后执行的。list()总是返回一个java.util.List对象,里面有零个或者多个值。list()可以返回实体对象,也可以返回实体对象的某属性或者某些属性。例如:
List<</span>Users> list1 = session.createQuery(" select * from Users ").list();
List list2 = session.createQuery(" select users.name from Users users ").list();
List nlist3 = session.createQuery(" select users.name, users.dept.name from Users users ").list();
List<</span>Users>list4 = session.createQuery(" select users.dept from Users users ").list();
第一个查询返回存储着Users对象的List。第二个查询返回存储着Users的name值(String类型)的List。第三个查询返回存储着由Users的name值、Users对应的Dept的name值组成的字符串数组(String[]类型)的List。第四个查询返回存储着Users对应的Dept的List,虽然是Users的一个属性,但仍然是Users类型。
12.2 查询结果同时返回多个对象
Query的list()方法返回java.util.List对象。List中一般存储完整的实体类对象。例如“select * from Users”,会将所有的Users都查询出来,包含Users类的所有即时加载的属性。
对于有些查询,只需要查询几个属性就够了,而不需要查询所有的实体类属性。这时候可以在HQL中指定要返回的部分。查询部分属性时,返回结果仍然是List类型,里面可能是单个的对象Object,也可能是对象数组Object[],还可能是List对象与Map对象。返回什么样的类型数据,由HQL语句决定。
12.2.1 返回List集合
返回结果还可以放到List中。查询时HQL采用“select new List(name1, name2, name3) from...”的形式。同样需要遍历List来获取返回的List,再遍历返回的List获取查询结果,实例代码如下:
// 查询三个字段,放入一个新的List集合中,再返回List集合对象list1
List list1 = session.createQuery(
" select new List(u.name, u.address,u.password) from Users u").list();
for (List li : list1) { // 遍历第一层List集合
for (Object o : li) { // 遍历第二层List集合(保存3个字段的集合)
System.out.println("" + o); // 输出对象Object
}
}
上述的代码中,在查询语句中把查询的字段放入List集合中,再把createQuery()查询的结果放入到List集合中。通过for循环两次遍历,把集合中的对象遍历出来。
12.2.2 返回对象数组Object[]
查询多个属性时,Hibernate将同时返回多个对象(以Object[]类型返回)。返回的数组是放到List中的,得到返回的数组需要遍历List对象,示例代码如下:
List list = session.createQuery(
" select u.name, u.address,u.password from Users u ").list(); // 查询Users中的多个属性值,返回list
for (Object[] obj : list) { // 遍历装有数组的list集合
for (Object object : obj) { // 遍历数组
System.out.println("" + obj); // 输出遍历结果Object
}
}
上述代码查询多个属性,返回的是数组,如果只查询一个属性,则不会返回数组,而直接返回该类型数据。例如“select u.name from Users u”,将返回List。
12.2.3 返回实体类对象
这里说的实体类对象是指Java的实体类对象。如果只查询部分属性,返回数组、List、Map时很方便,但是操作Object[]数组、List、Map等不如操作实体对象方便。所以实际上查询部分属性时,可以返回实体对象。HQL中也可以使用构造函数。示例代码如下:
List<</span>Users> list = session.createQuery(
“ select newUsers(u.name, u.password) from Users u ”) .list(); // HQL中使用Users类的构造函数
HQL中使用Users类的构造函数时,Users类中必须存在一个public Users(String name, String password)的构造函数。因为Hibernate是通过调用该构造函数完成返回值从Object[]数组转化到Users实体类的。
说明:HQL中使用构造函数时,对应的实体类中也必须有同样参数特征的构造函数。
12.2.4 返回Map集合
更实用的是返回Map类型。Map中将包含查询的列名、值。遍历List获得Map,从Map中直接取值就可以了,或者遍历Map,例如:
// 把需要查询的字段放到Map集合中,把查询的Map集合再返回List集合
List map = session.createQuery(
" select new Map(u.name as name, u.address as address, u.password as password) "
+ " from Users u ").list();
for (Map map1 : (List) map) { // 遍历List集合
System.out.println("Name: " + map1.get("name")); // 输出Map集合中的name属性
System.out.println("Password: " + map1.get("password")); // 输出Ma集合中的password属性
System.out.println("Address: " + map1.get("address")); // 输出Map集合address属性
}
12.3 HQL的高级应用
这一节将介绍HQL语言中的一些常用的高级应用,包括HQL中的条件查询、分页显示查询结果、级联查询以及其他的应用。
12.3.1 条件查询
HQL用where连接条件子句,语法类似于SQL。大部分SQL的规则对于HQL都适用,例如等于(=)、大于(>)、小于(<</font>)等。HQL的where子句中使用的是实体类的属性,或者是属性的属性。查询条件可以写在HQL中,也可以通过Query设置参数,示例代码如下:
session.createQuery(" select * from Users "
+ " where u.dept.name = null and u.age < :age ")
.setParameter("age", 23).list();
HQL的where子句中可以使用的运算符如下:
q 数学运算符:+、-、*、/。
q 比较操作符:=、!=、<>、>=、<=、like。
q 逻辑计算法:and、or、not。
q SQL操作符:in、not in、between、is null、is not null、is empty、number of等。
q 字符串连接:...||...或者concat(..., ...)。
q 时间日期函数:current_date()、current_time()、current_timestamp()。
q 时间日期函数:second(...)、minute(...)、hour(...)、day(...)、month(...)、year(...)。
q JPA定义的操作:substring()、trim()、lower()、upper()、length()、locate()、abs()、sqrt()、bit_length()、coalesce()、nullif()。
q 数据库支持的SQL标量函数:sign()、trunc()、rtrim()、sin()。
q 简单的跳转语句:case ... when ... then ... else ... end。
例如字符串连接:
List list = session.createQuery(
" select u.name || '所在部门为' || u.dept.name from Users u where u.dept != null ").list();
in子句查询:
List<</span>Users> list = session.createQuery(“ from Users where lower(trim(uu.name)) in (‘Jack’, ‘Macle’, ‘李四’) ”).list();
集合查询:
List<</span>Users> list = session.createQuery(“ from Users u where size(u.events) > 5 ”).list();
设置查询条件时,应尽量使用setParameter()传递参数,而不是将参数写进HQL语句。第一次执行SQL语句时,数据库会将该SQL语句进行编译,供下次查询使用。对于参数不同的相同查询,数据库将直接调用编译后的SQL,提高查询效率。
12.3.2 HQL中的统计函数
跟SQL一样,Hibernate也提供一系列的统计函数。Hibernate会把HQL的统计函数转化为底层数据库SQL支持的函数。
SQL里的常用统计函数比如count()、sum()、min()、max()、avg()、count(distinct ...)等也都能用在HQL里,语法与SQL一样,例如:
Number num = (Number) session.createQuery(
" select count(*) from Users u where u.name != null ")
.uniqueResult();
int count = num.intValue();
查询总数时并不总是返回Long类型。返回值类型由实体类的主键类型决定的。如果实体类的主键为short类型,则返回值可能为Integer类型。
12.3.3 HQL分页显示查询结果
分页显示是web数据库程序必备的功能。不同的数据库使用不同的方式实现分页,例如MySQL使用limit,Oracle使用rownum。Hibernate隐藏了所有的细节,只需要设置当前页数即可。
分页显示一般先查询记录总数,然后查询本页显示的记录。Hibernate通过Query查询记录,Query通过setFirstResult()设置分页的第一条记录,通过setMaxResults()设置取本页的数据数,示例代码如下:
//HQL的分页查询
Query q2 = session.createQuery("from Employees");//查询所有记录
int page=1; //设置默认的页数为1
q2.setFirstResult((page-1)*2); //每页起始数
q2.setMaxResults(5); //每页最最多显示的页数
List emps = q2.list();//返回list集合
for (Employees emp:emps) {
System.out.println(emp.getEmployeeId());//打印输出属性
}
分页显示一般会封装成Pagination组件。Pagination负责计算每页的起始记录、总页数等。使用实例见Servlet章节。
查询总数时并不总是返回Long类型。返回值类型由实体类的主键类型决定的。如果实体类的主键为short类型,则返回值可能为Integer类型。
12.3.4 HQL跨表查询
对于一般的跨表查询,表连接就足够了。Hibernate支持用“.”作为操作符获取属性,用法类似于JSP中的EL表达式。表连接查询适用于非集合属性,对于一般的跨表查询,只需要简单的使用属性就可以了。例如Users的name属性,Dept的name属性等,示例代码如下:
List<</span>Users> list = session.createQuery(
" select * from Users u where u.dept.name = 'Java开发部' ").list();
表面上该查询只涉及Users表,但实际上因为where子句条件用到了u.dept.name,将会查询Dept表与Users表。
12.3.5 HQL级联查询
有些查询需要使用级联查询。HQL支持SQL的级联查询,包括inner join、left join、right join、full join等。级联查询适用于集合属性,例如Users的dept集合属性。例如查询events集合属性中有“迟到”事件的cat,查询语句为:
List<</span>Users> list = session.createQuery(
" select * from Users u left join u.events e where e.description like :description ")
.setParameter("description", "%迟到%").list();
12.3.6 使用数据库SQL
HQL可以看作是是对所有数据库SQL的封装。HQL提供的功能是底层数据库SQL支持的,HQL只是将功能“翻译”成了底层SQL的功能。有些情况下,底层数据库会提供某种功能,但是可能HQL不支持。这时可以使用底层SQL,在专业术语上叫做本地SQL(Native SQL)。
使用数据库SQL查询时不能使用Query,要使用SQLQuery对象。例如在MySQL数据库中查询所有的变量:
SQLQuery sqlQuery = session.createSQLQuery(" show variables "); // 使用本地SQL查询所有的变量
List list = sqlQuery.list(); // 执行查询,把查询结果放到List集合中
for (Object[] object : list) { // 遍历集合中所有的属性
System.out.println(object [0] + ", " + object [1] + ", "); // 输出对象属性值
}
SQLQuery与Query一样,都也可以设置参数、分页显示等。SQLQuery返回的结果为List类型。也可以设置为实体类,使查询结果直接返回实体类对象,示例代码如下:
SQLQuery sqlQuery = session.createSQLQuery(" select * from users"); // 使用本地SQL查询
sqlQuery.addEntity(Users.class); // 设置输出类型括号中是实体类名
List< Users > list = sqlQuery.list(); // 返回List< Users >
如果设置的实体类与查询结果不一致,会抛出异常。
12.3.7 使用@注解配置命名查询
有些查询是常用的,Hibernate中可以把常用的查询命名,需要使用查询时只需要引用名称就可以了。命名查询一般配置在实体类中。有使用@注解配置命名查询和使用XML配置命名查询。
使用@注解配置实体类时,要使用@注解配置命名查询,用到的Java注解为@NamedQuery与@NamedNativeQuery。其中,@NamedQuery用于配置命名的HQL查询,@NamedNativeQuery用于配置命名的底层数据库SQL查询,实体类中的代码如下:
import javax.persistence.*;
@NamedQuery(name = "all users", query = " select * from Users")// 命名查询,name是查询语句的名称
@NamedNativeQuery(name = "all users", query = "select * from users") // 命名本地查询
@Entity // Entity配置
@Table(name = "users") // Table配置
public class Users {
//这里省略了类中的内容
}
上述代码中,命名查询的查询语句中Users是实体类的名称,命名本地查询的查询语句中users是数据库表名。
12.3.8 使用@QueryHint扩展查询
命名查询中,允许使用@QueryHint对命名查询设置JPA扩展。JPA规范允许对JPA进行一些功能上的扩展,以加速查询性能、提供其他功能等。示例代码如下:
@NamedQuery(name = "all users name", query = " select * from Users u where u.name = :name ", hints = { @QueryHint(name = "org.hibernate.callable", value = "true") })
使用@QueryHint时,要把@QueryHint写在hints中,hints的格式是“hints={}”,需要写的@QueryHint内容写在大括号中。org.hibernate.callable 的布尔变量值表明这个查询是否是一个存储过程。value=”true”表示这个查询是存储过程。
12.3.9 同时设置多个命名查询
一个实体类不能配置多个@NamedQuery。如果有多个命名查询,需要使用@NamedQueries配置。@NamedQueries中可以配置多个@NamedQuery,示例代码如下:
@NamedQueries(value = {
@NamedQuery(name = "all users", query = " select u from Users u "),
@NamedQuery(name=" users name", query=" select u from Users u where u.name = :name ",),
@NamedQuery(name=" users for dept",query="select u from Users u where u.dept.name = :dept ") })
当需要使用到命名查询的时候,直接在程序中调用,程序中这样使用命名查询,如果有参数,需要设置参数,示例代码如下:
Query query = session.getNamedQuery("users name ").setParameter(“name”, “Jack”);
List<</span>Users> list = query.list();
12.3.10 在XML中配置命名查询
如果实体类使用XML文件配置映射关系时,命名查询需要配置在hbm.xml实体类映射文件中。命名查询使用配置,要配置中实体类的后面,name配置查询的名称,可配置返回数据的类型。示例代码如下:

<?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. java.vo"><!-- 实体类所在的包 -->
<class name="Employee" table="emp">
<id name="empno" column="empno" length="32"> <!-- 主键-->
<generator class="native">
</generator>
</id>
<property name="empname" length="32"></property>
<!-- 映射多对一的关系 -->
<many-to-one name="dept" class="Dept" column="depno" cascade="all"></many-to-one >
</class>
<sql-query name="emp name"> <!-- 配置命名查询 -->
<![CDATA[
select e from Employee e where e. empname = :name
]]>
<return alias="" class=" com.java.vo. Employee " /><!--返回类型 这里返回的是Employees类对象-->
</sql-query>
<sql-query name="emp for dept"> <!-- 命名查询 -->
<![CDATA[
select e from Employee e where e.dept.name = :name
]]>
<return alias="" class=" com.java.vo. Employee " /><!--返回类型-->
</sql-query>
</hibernate-mapping>

12.4 本章小结
Hibernate使数据持久层以面向对象的方式编程,直接存储、操作Java对象,使用HQL查询数据。

Java_Web三大框架之Hibernate+HQL语言基础的更多相关文章

  1. Java_Web三大框架之Hibernate+jsp+HQL分页查询

    分页查询无处不在.使用Hibernate+jsp+HQL进行分页查询. 第一步:编写房屋实体类和House.hbm.xml映射. /* * 房屋实体类 */ public class House { ...

  2. Java_Web三大框架之Hibernate+jsp+selvect+HQL查询数据

    俗话说:"好记性不如烂笔头".本人学习Hibernate也有一个星期了,对Hibernate也有一个初步的了解.下面对Hibernate显示数据做个笔记,使用租房系统的Hibern ...

  3. Java_Web三大框架之Hibernate+jsp+selvect+HQL注册用户

    Hibernate比SQL语句简单多了,代码冗余少,切方便简洁明了.下面用Hibernate+jsp+selvect+HQL来实现注册用户. 第一步:编写用户实体类和Users2.hbm.xml映射. ...

  4. Java_Web三大框架之Hibernate+jsp+selvect+HQL登入验证

    刚开始接触Hibernate有些举手无措,觉得配置信息太多.经过一个星期的适应,Hibernate比sql简单方便多了.下面做一下Hibernate+jsp+selvect+HQL登入验证. 第一步: ...

  5. Java_Web三大框架之Hibernate 入门(一)

    一.Hibernate简介: Hibernate作者——Gavin King Hibernate创始人 < Hibernate in action >作者 EJB 3.0的Entity b ...

  6. Java_Web三大框架之Hibernate操作数据库(三)

    使用Hibernate操作数据库需要七个步骤: (1)读取并解析配置文件 Configuration conf = newConfiguration().configure(); (2)读取并解析映射 ...

  7. Java_Web三大框架之Hibernate增删改查

    下面介绍一下Hibernate的增删改查. 第一步:编写用户实体类以及User.hbm.xml映射 package com.msl.entity; public class User { privat ...

  8. Java_Web三大框架之Hibernate配置文件(二)

    下面介绍一下编写Hibernate的配置文件,使用Hibernate操作数据库. 开始部署:下载需要的jar包               下载Hibernate           Hibernat ...

  9. Java_Web三大框架之Struts2

    今天正式接触Java_Web三大框架之Struts2框架.对于初学者来说,先来了解什么是框架技术: 一.“框架技术”帮我们更快更好地构建程序: 1.是一个应用程序的半成品 2.提供可重用的公共结构 3 ...

随机推荐

  1. hdu_1205_吃糖果_201404021440

    吃糖果 Time Limit: 6000/3000 MS (Java/Others)    Memory Limit: 65535/32768 K (Java/Others) Total Submis ...

  2. Ubuntu 16.04安装Synaptic Package Manager图形化APT管理工具

    安装: sudo apt-get install synaptic 启动:

  3. Android 内存管理

    1.Activity中的对象生命周期勿大于Activity的生命周期.OOM演示样例代码例如以下: private static Drawable sBackground; @Override pro ...

  4. git 手动操作

    git 手动操作 以下所有的情况都需要在上面那个目录下: 查看改动: git status // 所有改动都在这里. 提交代码: git add <file_name> // 把代码放到 ...

  5. HDU 5311 Hidden String (优美的暴力)

    Hidden String Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 262144/262144 K (Java/Others) ...

  6. LeetCode总结--二分查找篇

    二分查找算法尽管简单,但面试中也比較常见.经经常使用来在有序的数列查找某个特定的位置.在LeetCode用到此算法的主要题目有: Search Insert Position Search for a ...

  7. PhoneGap:JS跨域请求

    PhoneGap开发,理论上好处多多.但因为javascript是其中的主角,并且是直接存放于手机,跟服务器数据交互,就会有一个跨域访问的问题. 当然,这个问题肯定有解决方案,不然的话,这种利用Pho ...

  8. 3736 【HR】万花丛中2

    3736 [HR]万花丛中2  时间限制: 1 s  空间限制: 128000 KB  题目等级 : 黄金 Gold 题解       题目描述 Description HR神犇在成功攻略ZX后,花心 ...

  9. U4699 鸡蛋

    U4699 鸡蛋 0通过 37提交 题目提供者飞翔 标签 难度尚无评定 提交 最新讨论 暂时没有讨论 题目背景 调皮的kkk准备恶搞他的同学兼朋友——你! 题目描述 kkk准备从楼上扔鸡蛋下来砸在lz ...

  10. AngularJS2.0 hello world例子——引入这么多额外的依赖库真是很忧伤啊

    初识Angular2 写一个Angular2的Hello World应用相当简单,分三步走: 1. 引入Angular2预定义类型 import {Component,View,bootstrap} ...