Hibernate之HQL查询
一、Hibernate 提供了以下几种检索对象的方式:
- 导航对象图检索方式: 根据已经加载的对象导航到其他对象 OID 检索方式: 按照对象的 OID 来检索对象
- HQL 检索方式:使用面向对象的 HQL 查询语言
- QBC 检索方式: 使用 QBC(Query By Criteria) API 来检索对象. 这种
API 封装了基于字符串形式的查询语句, 提供了更加面向对象的查询接口. - 本地 SQL 检索方式: 使用本地数据库的 SQL 查询语句
二、HIbernate的HQL查询
1. HQL(Hibernate Query Language) 是面向对象的查询语言, 它和 SQL 查询语言有些相似. 在 Hibernate 提供的各种检索方式中, HQL 是使用最广的一种检索方式. 它有如下功能:
在查询语句中设定各种查询条件
- 支持投影查询, 即仅检索出对象的部分属性
- 支持分页查询
- 支持连接查询
- 支持分组查询, 允许使用 HAVING 和 GROUP BY 关键字
- 提供内置聚集函数, 如 sum(), min() 和 max()
- 支持子查询
- 支持动态绑定参数
- 能够调用 用户定义的 SQL 函数或标准的 SQL 函数
2. HQL 检索方式包括以下步骤:
a、通过 Session 的 createQuery() 方法创建一个 Query 对象, 它包括一个 HQL 查询语句. HQL 查询语句中可以包含命名参数
b、动态绑定参数
c、调用 Query 相关方法执行查询语句.
三、各种查询示例代码:
1、首先搭建测试环境:
两个测试实体类:
Employee类:
public class Employee {
private Integer id;
private String name;
private float salary;
private String email;
private Department dept;
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public float getSalary() {
return salary;
}
public void setSalary(float salary) {
this.salary = salary;
}
public String getEmail() {
return email;
}
public void setEmail(String email) {
this.email = email;
}
public Department getDept() {
return dept;
}
public void setDept(Department dept) {
this.dept = dept;
}
public Employee(float salary, String email, Department dept) {
super();
this.salary = salary;
this.email = email;
this.dept = dept;
}
public Employee() {
}
@Override
public String toString() {
return "Employee [id=" + id + "]";
}
}
Department类:
public class Department {
private Integer id;
private String name;
private Set<Employee> emps=new HashSet<Employee>();
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Set<Employee> getEmps() {
return emps;
}
public void setEmps(Set<Employee> emps) {
this.emps = emps;
}
@Override
public String toString() {
return "Department [id=" + id + ", name=" + name + "]";
}
}
2个实体类对应的hbm配置文件:
<!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<!-- Generated 2015-10-31 23:07:48 by Hibernate Tools 3.4.0.CR1 -->
<hibernate-mapping package="com.elgin.hibernate.entity">
<class name="Employee" table="EMPLOYEE">
<id name="id" type="java.lang.Integer">
<column name="ID" />
<generator class="native" />
</id>
<property name="name" type="java.lang.String">
<column name="NAME" />
</property>
<property name="salary" type="float">
<column name="SALARY" />
</property>
<property name="email" type="java.lang.String">
<column name="EMAIL" />
</property>
<many-to-one name="dept" class="Department" >
<column name="DEPT_ID" />
</many-to-one>
</class>
<query name="salaryEmp">
<![CDATA[
from Employee e where e.salary> :minSal and e.salary < :maxSal
]]>
</query>
</hibernate-mapping>
<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<!-- Generated 2015-10-31 23:07:48 by Hibernate Tools 3.4.0.CR1 -->
<hibernate-mapping package="com.elgin.hibernate.entity">
<class name="Department" table="DEPARTMENT">
<id name="id" type="java.lang.Integer">
<column name="ID" />
<generator class="native" />
</id>
<property name="name" type="java.lang.String">
<column name="NAME" />
</property>
<set name="emps" table="EMPLOYEE" inverse="true" lazy="true">
<key>
<column name="DEPT_ID" />
</key>
<one-to-many class="Employee" />
</set>
</class>
</hibernate-mapping>
Hibernate配置文件:hibernate.cfg.xml
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE hibernate-configuration PUBLIC
"-//Hibernate/Hibernate Configuration DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-configuration-3.0.dtd">
<hibernate-configuration>
<session-factory>
<!-- hibernate数据库连接信息配置 -->
<property name="connection.username">root</property>
<property name="connection.password">root123</property>
<property name="connection.url">jdbc:mysql://localhost:3306/hibernate</property>
<property name="connection.driver_class">com.mysql.jdbc.Driver</property>
<!-- hibernate基本配置 -->
<!-- hibernate的数据库方言 -->
<property name="dialect">org.hibernate.dialect.MySQL5InnoDBDialect</property>
<property name="hbm2ddl.auto">update</property>
<property name="show_sql">true</property>
<property name="format_sql">true</property>
<!--设置hibernate事务的隔离级别 -->
<property name="connection.isolation">2</property>
<!-- 需要关联的hibernate映射文件 hbm.xml文件 -->
<mapping resource="com/elgin/hibernate/entity/Department.hbm.xml"/>
<mapping resource="com/elgin/hibernate/entity/Employee.hbm.xml"/>
</session-factory>
</hibernate-configuration>
Hibernate查询单元测试类:
public class HibernateTest2 {
//如此声明只为方便测试,生产环境不能这么用
private SessionFactory sessionFactory;
private Session session;
private Transaction transcation;
@Before
public void init(){
Configuration cfg=new Configuration().configure();
ServiceRegistry serviceRegistry=new ServiceRegistryBuilder().applySettings(cfg.getProperties()).buildServiceRegistry();
sessionFactory=cfg.buildSessionFactory(serviceRegistry);
session=sessionFactory.openSession();
transcation=session.beginTransaction();
}
public void insert(int i){
Employee employee=new Employee();
employee.setName("name"+i);
employee.setEmail("name"+i+"@qq.com");
employee.setSalary(1000*i);
session.save(employee);
}
@Test
//初始化2个表中的数据,方便查询
public void test(){
for (int i = 14; i < 21; i++) {
insert(i);
}
}
@After
public void destory(){
transcation.commit();
session.close();
sessionFactory.close();
}
}
上述类为基础测试类,如下的测试代码均需加入到上述类中运行。至此,测试环境搭建完成,下面逐一进行测试:
2 绑定参数:
- Hibernate 的参数绑定机制依赖于 JDBC API 中的 PreparedStatement 的预定义 SQL 语句功能.
- HQL 的参数绑定由两种形式:
按参数名字绑定: 在 HQL 查询语句中定义命名参数, 命名参数以 “:” 开头.
按参数位置绑定: 在 HQL 查询语句中用 “?”来定义参数位置
- 相关方法:
setEntity(): 把参数与一个持久化类绑定。
setParameter(): 绑定任意类型的参数. 该方法的第三个参数显式指定 Hibernate 映射类型。
测试代码:
@Test
public void testHQLNamedParameters(){
//1.创建 Query 对象
// 基于命名参数
String HQL="FROM Employee e WHERE e.salary> :salary AND e.email LIKE :email";
Query query=session.createQuery(HQL);
//2. 动态绑定参数
query.setFloat("salary", 6000).setString("email", "%a%");
//3. 执行查询
List<Employee> emps = query.list();
System.out.println(emps.size());
}
@Test
public void testHQL(){
//1.创建 Query 对象
// 基于位置的参数
String HQL="FROM Employee e WHERE e.salary> ? AND e.email LIKE ?";
Query query=session.createQuery(HQL);
//2. 动态绑定参数
// Query对象调用setXxx方法,支持方法链的编程
query.setFloat(0, 6000).setString(1, "%a%");
//3. 执行查询
List<Employee> emps = query.list();
System.out.println(emps.size());
}
3 分页查询:
- setFirstResult(int firstResult): 设定从哪一个对象开始检索, 参数 firstResult表示这个对象在查询结果中的索引位置, 索引位置的起始值为 0. 默认情况下, Query 从查询结果中的第一个对象开始检索
- setMaxResults(int maxResults): 设定一次最多检索出的对象的数目. 在默认情况下, Query 和 Criteria 接口检索出查询结果中所有的对象
/**
* HQL分页查询
*
*/
@Test
public void testPageQuery(){
String HQL="from Employee";
int pageNo=2;
int pageSize=5;
List<Employee> emps= session.createQuery(HQL)
.setFirstResult((pageNo-1)*pageSize)
.setMaxResults(pageSize)
.list();
System.out.println(emps);
}
4.在映射文件中定义命名查询语句
Hibernate 允许在映射文件中定义字符串形式的查询语句.
元素用于定义一个 HQL 查询语句, 它和 元素并列.
在程序中通过 Session 的 getNamedQuery() 方法获取查询语句对应的 Query 对象.
本例在Employee.hbm.xml映射文件中定义了如下:
<query name="salaryEmp">
<![CDATA[
from Employee e where e.salary> :minSal and e.salary < :maxSal
]]>
</query>
之后就可以使用如下代码来使用次查询语句:
/**
* HQL命名查询(HQL语句配置在hbm文件中的query标签中,使用CDATA包裹)
*
*/
@Test
public void testNamedQuery(){
Query query=session.getNamedQuery("salaryEmp");
List<Employee> emps=query.setFloat("minSal", 2000)
.setFloat("maxSal", 5000)
.list();
System.out.println(emps);
}
5.投影查询:
- 投影查询: 查询结果仅包含实体的部分属性. 通过 SELECT 关键字实现.
- Query 的 list() 方法返回的集合中包含的是数组类型的元素, 每个对象数组代表查询结果的一条记录
- 可以在持久化类中定义一个对象的构造器来包装投影查询返回的记录, 使程序代码能完全运用面向对象的语义来访问查询结果集.
- 可以通过 DISTINCT 关键字来保证查询结果不会返回重复元素
测试代码:
/**
* HQL投影查询,结果类型为List<Object[]>
*
*/
@Test
public void testFieldQuery(){
String hql="select e.email,e.salary,e.dept from Employee e where e.dept=:dept";
Department dept=new Department();
dept.setId(6);
Query query=session.createQuery(hql).setEntity("dept", dept);
List<Object[]> emps=query.list();
for (Object[] employee : emps) {
System.out.println(Arrays.asList(employee));
}
}
若想要把投影查询的结果映射到对象上,则需要在Employee对象加入相应的构造方法,映射对象示例:
/**
* HQL投影查询,结果类型为List<Employee>
* 1.HQL语句中使用new关键字将结果映射到对象上,
* 前提是Employee对象中有对应的构造方法
*/
@Test
public void testFieldQuery2(){
String hql="select new Employee(e.salary,e.email,e.dept) from Employee e where e.dept=:dept";
Department dept=new Department();
dept.setId(6);
Query query=session.createQuery(hql).setEntity("dept", dept);
List<Employee> emps=query.list();
for (Employee employee : emps) {
System.out.println(employee.getEmail());
System.out.println(employee.getSalary());
System.out.println(employee.getDept());
}
}
6.报表查询
报表查询用于对数据分组和统计, 与 SQL 一样, HQL 利用 GROUP BY 关键字对数据分组, 用 HAVING 关键字对分组数据设定约束条件.
在 HQL 查询语句中可以调用以下聚集函数:
count()
min()
max()
sum()
avg()
示例:
/**
* 报表查询,可以使用相关聚集函数
*
*/
@Test
public void testGroupBy(){
String hql="select min(e.salary),max(e.salary),e.dept from Employee e"
+ " group by e.dept"
+ " having min(e.salary) > :min";
Query query=session.createQuery(hql).setFloat("min", 3000);
List<Object[]> emps=query.list();
for (Object[] objects : emps) {
System.out.println(Arrays.asList(objects));
}
}
7.HQL迫切左外连接:
- LEFT JOIN FETCH 关键字表示迫切左外连接检索策略.
- list() 方法返回的集合中存放实体对象的引用, 每个 Department 对象关联的 Employee 集合都被初始化,存放所有关联的 Employee 的实体对象.
- 查询结果中可能会包含重复元素, 可以通过一个 HashSet 来过滤重复元素
/**
* HQL 迫切左外连接
*/
@Test
public void testLeftJoinFetch(){
String hql="select distinct d from Department d left join fetch d.emps";
Query query=session.createQuery(hql);
List<Department> depts=query.list();
for (Department dept : depts) {
System.out.println(dept.getName()+"-"+dept.getEmps().size());
}
}
7.HQL 左外连接:
- LEFT JOIN 关键字表示左外连接查询.
- list() 方法返回的集合中存放的是对象数组类型
- 根据配置文件来决定 Employee 集合的检索策略(是否延迟加载)
- 如果希望 list() 方法返回的集合中仅包含 Department 对象, 可以在HQL 查询语句中使用 SELECT 关键字
/**
* HQL 左外连接
*/
@Test
public void testLeftJoin(){
String hql="select distinct d from Department d left join d.emps";
Query query=session.createQuery(hql);
List<Department> depts=query.list();
for (Department dept : depts) {
System.out.println(dept.getName()+"-"+dept.getEmps().size());
}
}
综上迫切左外连接和左外连接:
- 如果在 HQL 中没有显式指定检索策略, 将使用映射文件配置的检索策略.
- HQL 会忽略映射文件中设置的迫切左外连接检索策略, 如果希望 HQL 采用迫切左外连接策略, 就必须在 HQL 查询语句中显式的指定它
- 若在 HQL 代码中显式指定了检索策略, 就会覆盖映射文件中配置的检索策略
Hibernate之HQL查询的更多相关文章
- hibernate的hql查询
1.概念介绍 1.Query是Hibernate的查询接口,用于从数据存储源查询对象及控制执行查询的过程,Query包装了一个HQL查询语句. 2.HQL是Hibernate Query Langua ...
- 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查询语句总结
这篇随笔将会记录hql的常用的查询语句,为日后查看提供便利. 在这里通过定义了三个类,Special.Classroom.Student来做测试,Special与Classroom是一对多,Class ...
- Hibernate(九)HQL查询
一.Hibernate提供的查询方式 OID查询方式:主键查询.通过get()或者load()方法加载指定OID的对象查询结果为一个 HQL查询方式:通过Query接口使用HQL语言进行查询 QBC查 ...
- Hibernate 笔记 HQL查询 条件查询,聚集函数,子查询,导航查询
在hibernate中进行多表查询,每个表中各取几个字段,也就是说查询出来的结果集并没有一个实体类与之对应,如何解决这个问题? 解决方案一,按照Object[]数据取出数据,然后自己组bean 解决方 ...
- Hibernate 、Hql查询和Criteria查询
HQL查询: public Object query(String name){ Session s=null; try{ s=HibernateSessionFactory.getSession() ...
- Hibernate之HQL查询的一些例子
Hibernate配备了一种非常强大的查询语言,就是HQL(hibernate query language),HQL看上去很像sql,但只是语法结构上相似,HQL是一种面向对象的查询,他可以理解继承 ...
- Hibernate 中Hql 查询中间表的用法
案例简述: 项目中存在User 用户表 和 Role 角色表 它们之间是多对多的关系 在User类定义中 使用hibernate注解 //角色列表 @ManyToMany(targetEntity = ...
随机推荐
- sql 2005 同义词
--> Title : SQL Server2005 Synonym的使用 --> Author : wufeng4552 --> Date : 2009-10-30 1.Sy ...
- java中四种操作(dom、sax、jdom、dom4j)xml方式详解与比较
1)DOM(JAXP Crimson解析器) DOM是用与平台和语言无关的方式表示XML文档的官方W3C标准.DOM是以层次结构组织的节点或信息片断的集合.这个层次结构允许开发人员在树中寻找特 ...
- linux中压缩与解压缩命令小结
linux中压缩与解压操作非常常见,其命令参数也非常的多,这里只介绍最经常用的带打包文件的几种压缩和解压方式和几个最常用的参数. 现在最常用的压缩和解压工具是gzip和bzip2,这两种工具不能相互解 ...
- int string相互转换
一.itoa()和atoi() 注意:这两个函数并不是标准的C函数,而是windows环境下特有的函数. 1.itoa #include<iostream> #include<str ...
- Android应用程序中应用图标和名字的设置
在AndroidManifest.xml文件中设android:icon和 android:label指定名字和图标的位置,如: <application android:icon=" ...
- poj 1845 Sumdiv (数论)
题目链接 题意:求 A^B的所有约数之和对9901取模后的结果. 分析: 看了小优的博客写的. 分析来自 http://blog.csdn.net/lyy289065406/article/detai ...
- Codeforces Round #239 (Div. 2)
做了三个题,先贴一下代码...终于涨分了 A. Line to Cashier 水题 #include <iostream> #include <cstdio> #includ ...
- Java I/O 扩展
Java I/O 扩展 标签: Java基础 NIO Java 的NIO(新IO)和传统的IO有着相同的目的: 输入 输出 .但是NIO使用了不同的方式来处理IO,NIO利用内存映射文件(此处文件的含 ...
- Spring下载
Spring官网改版后找了好久都没有找到直接下载Jar包的链接,下面汇总些网上提供的方法,亲测可用. 1.直接输入地址,改相应版本即可:http://repo.springsource.org/lib ...
- 聚焦 SQL 数据库活动异地复制
Tobias Ternstrom US-DS-PM 首席部门项目经理 本文作为一系列业务连续性和灾难恢复文章的开篇,概述了业务连续性的各种场景,然后重点介绍 SQL 数据库高级服务级别提供的活动异地 ...