一、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查询的更多相关文章

  1. hibernate的hql查询

    1.概念介绍 1.Query是Hibernate的查询接口,用于从数据存储源查询对象及控制执行查询的过程,Query包装了一个HQL查询语句. 2.HQL是Hibernate Query Langua ...

  2. Hibernate五 HQL查询

    HQL查询一 介绍1.HQL:Hibernate Query Language,是一种完全面向对象的查询语言.使用Hibernate有多重查询方式可供选择:hibernate的HQL查询,也可以使用条 ...

  3. Hibernate 的hql查询简介【申明:来源于网络】

    Hibernate 的hql查询简介[申明:来源于网络] Hibernate 的hql查询简介:http://blog.csdn.net/leaf_130/article/details/539329 ...

  4. hibernate的hql查询语句总结

    这篇随笔将会记录hql的常用的查询语句,为日后查看提供便利. 在这里通过定义了三个类,Special.Classroom.Student来做测试,Special与Classroom是一对多,Class ...

  5. Hibernate(九)HQL查询

    一.Hibernate提供的查询方式 OID查询方式:主键查询.通过get()或者load()方法加载指定OID的对象查询结果为一个 HQL查询方式:通过Query接口使用HQL语言进行查询 QBC查 ...

  6. Hibernate 笔记 HQL查询 条件查询,聚集函数,子查询,导航查询

    在hibernate中进行多表查询,每个表中各取几个字段,也就是说查询出来的结果集并没有一个实体类与之对应,如何解决这个问题? 解决方案一,按照Object[]数据取出数据,然后自己组bean 解决方 ...

  7. Hibernate 、Hql查询和Criteria查询

    HQL查询: public Object query(String name){ Session s=null; try{ s=HibernateSessionFactory.getSession() ...

  8. Hibernate之HQL查询的一些例子

    Hibernate配备了一种非常强大的查询语言,就是HQL(hibernate query language),HQL看上去很像sql,但只是语法结构上相似,HQL是一种面向对象的查询,他可以理解继承 ...

  9. Hibernate 中Hql 查询中间表的用法

    案例简述: 项目中存在User 用户表 和 Role 角色表 它们之间是多对多的关系 在User类定义中 使用hibernate注解 //角色列表 @ManyToMany(targetEntity = ...

随机推荐

  1. Junit使用教程(四)

    一.会用Spring测试套件的好处 在开发基于Spring的应用时,如果你还直接使用Junit进行单元测试,那你就错过了Spring为我们所提供的饕餮大餐了.使用Junit直接进行单元测试有以下四大不 ...

  2. oracle Instance status: READY–lsnrctl status|start|stop

    监听器启动,并不一定会认识数据库实例,启动监听器,请判别相关实例是否 READY [oracle@redhat4 ~]$ lsnrctl status LSNRCTL for Linux: Versi ...

  3. 1124. Mosaic(dfs)

    1124 需要想那么一点点吧 一个连通块中肯定不需要伸进手不拿的情况 不是一个肯定会需要这种情况 然后注意一点 sum=0的时候 就输出0就可以了 不要再减一了 #include <iostre ...

  4. disable-linux-firewall-under-centos-rhel-fedora

    http://www.cyberciti.biz/faq/disable-linux-firewall-under-centos-rhel-fedora/

  5. hdu 4970 Killing Monsters (思维 暴力)

    题目链接 题意: 有n座塔,每座塔的攻击范围为[l,r],攻击力为d,有k个怪兽从这些塔前面经过,第i只怪兽初始的生命力为hp,出现的位置为x,终点为第n个格子.问最后有多少只怪兽还活着. 分析: 这 ...

  6. mysql_create_frm

    http://www.cnblogs.com/jiangxu67/p/4755097.html http://www.cnblogs.com/jiangxu67/p/4755097.html http ...

  7. 无法加载 DLL“rasapi32.dll”: 动态链接库(DLL)初始化例程失败。

    无法加载 DLL“rasapi32.dll”: 动态链接库(DLL)初始化例程失败. 在Asp.Net项目中使用WebClient或HttpWebRequest时出现以上错误 解决方案:把以下代码放在 ...

  8. 一个java高级工程师的进阶之路

    宏观方面 一. JAVA.要想成为JAVA(高级)工程师肯定要学习JAVA.一般的程序员或许只需知道一些JAVA的语法结构就可以应付了.但要成为JAVA(高级) 工程师,您要对JAVA做比较深入的研究 ...

  9. [反汇编练习] 160个CrackMe之010

    [反汇编练习] 160个CrackMe之010. 本系列文章的目的是从一个没有任何经验的新手的角度(其实就是我自己),一步步尝试将160个CrackMe全部破解,如果可以,通过任何方式写出一个类似于注 ...

  10. 分析一下FastDFS_java_client中TestClient.java这个文件以及跟它关联的这条线

    本来先打算上个图来说明一下这条线的,可是我的画图工具还没有安装好,我先把跟TestClient.java相关的几个文件代码贴上来,但是由于代码行数还是不少的,所以请大家阅读文章的时候先不要展开代码,等 ...