Hibernate入门6.Hibernate检索方式 20131128

代码下载 链接: http://pan.baidu.com/s/1Ccuup 密码: vqlv

Hibernate的整体框架已经初步掌握,ORM持久层框架核心的是如何高效的和数据库进行交互以及如何交互。包括数据的增删改查、SQL查询还是HQL查询、查询技巧、离线查询等等。本次主要学习的是Hibernate的检索方式。

Hibernate检索方式

Hibernate提供了多种查询方式进行各种查询。前面已经了解了session的get() load()的方法检索指定id的对象,还有其他的检索方式:

导航对象图检索方式:根据已经加载的对象,利用对象之间的关联关系,导航到其他对象,比如customer.getOrders().iterator()可以导航到一个Order对象

OID检索方式:按照对象的OID来检索对象,可以使用session的load()和get()方法。

HQL方式:使用Hibernate Query Language(HQL)查询语言检索对象,Hibernate中提供了Query接口,该接口是HQL的查询接口,能够执行各种复杂的HQL查询语言。

QBC检索方式:使用Query By Criteria(QBC)API来检索对象,该API提供了更好的面向对象的接口

本地的SQL检索方式:使用数据库的SQL语言,Hibernate负责把检索到的JDBC ResultSet结果集映射为持久化对象图。

其中HQL和QBC是最为常见的,强大的查询方式:

HQL:他是面向对象的查询语言,其操作的是类、对象和属性,所以说HQL是面相对象的查询语言。

语法规则:

[select attribute_name_list]

from ClassName [as ]

[where condition]

[group by ] // select count(o) Order o group by o.customer

[having ]

[order by]

QBC也被称为条件查询,是完全面相对象的查询方式,主要通过下面的类实现

Criteria: 代表依次查询

Criterion:代表一个查询条件

Restrictions: 产生查询条件的工具类

常见的步骤是:获取Session对象,并且使用某个类的Class对象作为参数调用session的createCriteria()方法创建Criteria对象,调用criteria的add方法增减查询条件,执行Criteria的list()获得查询结果集到List接口中。。

HQL和QBC两者各有优点,但是HQL更加强大,类似SQL,QBC是通过特定的API执行的面向对象的查询,在动态查询的时候,QBC比HQL有优势。

下面开始详细的学习HQL和QBC的查询方式。

1.Query和Criteria接口

Query和Criteria接口是Hibernate的查询接口,用于向数据库查询对象,以及控制执行查询过程。Criteria接口完全封装了基于字符串形式的查询语句,比Query接口更加面相对象。

Query接口

HQL方式的查询依赖于Query接口,每一个Query实例都会对应一个查询对象,Query利用session的createQuery(String hql)接口获得一个实例:

int executeQuery();执行更新或者是删除操作,返回值是受影响的记录数

Iterator iterator()返回一个Iterator对象,用于迭代查询的结果集,首先检索ID字段,然后根据ID字段到Hibernate的一级、二级缓存中查找,如果找到则返回,反之执行额外的select语句,根据ID查询数据库,如果在缓存中,这种方式比list()性能高

List list();返回list类型的结果集,如果是投影查询,返回的是 Object[]

Query setFirstResult(int first);设置开始检索的位置,默认是0

Query setMaxResult(int max);设置一次最多检索的对象数目,默认是所有的对象,通常是和setFirstResult配合使用实现分页查询

Object uniqueResult(); 返回单个对象。如果没有查询到结果返回null,通常是和setMaxResult()配合使用,用于返回单个结果

Query setString(String name, String value);绑定映射类型中为string类型的参数

Query setEntity(String name, Object val);把参数和一个持久化对象绑定

Query setParameter(String name, Object value);用于绑定任意形式的参数

Query setProperties(String name,Object value):把命名参数和一个对象的属性值绑定

Criteria接口

Criteria接口表示的一次查询,该查询不具备任何数据筛选的功能。Criteria本身就是一个查询容器,具体的查询条件可以使用add的方法加入到Criteria实例中,开发人员不用编写SQL或者是HQL实现对于数据库的查询,同时QBC编译的时候就进行解析,便于查找错误,他的接口:

Criteria add (Criterion cri);增加查询条件

Criteria addOrder(Order order);增加排序规则,调用Order的asc()或者是desc()

Criteria createCriteria(String path);在相互关联的持久化类之间建立约束条件

List list() 返回list的结果集

Criteria setFirstResult(int first);

Cirteria setMaxResult(int max);

Object uniqueResult();

Criteria setProjection(Projection projectionf);设定统计函数实现分组统计功能,Projection类型的对象代表一个统计函数。

2.使用别名

通过HQL检索一个类的实例的时候,如果在查询语句的时候需要引用该类,一般会给他取一个别名,以便于引用:

from Customer as c where c.realName = ‘yang’//也可以将as关键字省略

form Customer c where c.realName=’yang’

同时在HQL查询语言中的关键字是不区分大小写的,但习惯使用的是小写

QBC检索方式不需要由应用程序显示的指定类的别名,Hibernate会自动把查询语句中的根节点实体赋予this

List result =

session.createCriteria(Customer.class).add(Restrictions.eq(“userName”,”yang”)).list();

等价于

List result =

session.createCriteria(Customer.class).add(Restrictions.eq(“this.userName”,”yang”)).list();

3.结果排序

HQL结果排序 采用的是在HQL中添加order by 关键字实现对于查询结果的排序。

Session session  = HibernateUtil.getSession();

String hql = "from Customer as c order by c.userName desc";

Query query = session.createQuery(hql);

List<Customer> list = query.list();

for(Customer customer : list){

System.out.println(customer);

}

QBC排序,采用的是org.hibernate.criterion.Order类实现对于查询结果的排序。Order代表排序类,其中asc()和desc()表示的是静态排序方法

public static void printUserNameByAsc(){

Session session = HibernateUtil.getSession();

Criteria criteria = session.createCriteria(Customer.class);

criteria.addOrder(org.hibernate.criterion.Order.asc("userName"));

List<Customer> list = criteria.list();

for(Customer customer : list){

System.out.println(customer.getUserName());

}

HibernateUtil.closeSession();

}

4.分页查询

HQL使用的是Query接口中的setFirstResult(int first)&& setMaxResult(int max)的方法结合实现

public static void listPageByQuery(int pageNo,int perPageNum){

Session session = HibernateUtil.getSession();

String hql = "form Customer as c where true order by c.id asc";

Query query = session.createQuery(hql);

query.setFirstResult((pageNo-1)*perPageNum);

query.setMaxResults(perPageNum);

List<Customer> list = query.list();

for(Customer customer : list){

System.out.println(customer.getUserName());

}

HibernateUtil.closeSession();

}

public static void listPageByCriteria(int pageNo, int perPageNum){

Session session = HibernateUtil.getSession();

Criteria criteria = session.createCriteria(Customer.class);

criteria.setFirstResult((pageNo-1)*perPageNum);

criteria.setMaxResults(perPageNum);

List<Customer> list = criteria.list();

for(Customer customer : list){

System.out.println(customer.getUserName());

}

HibernateUtil.closeSession();

}

5.检索一条记录

HQL和QBC都会使用setMaxResult(1),然后调用uniqueResult();就会返回一个Object的类型的对象。如果结果只会包含一个对象的话,那么可以不设置setMaxResult(),但是当检索的结果中包含了多个结果的时候,没有调用setMaxResult()的时候就会抛出异常NonUniqueResultException。

6.设定查询条件

在HQL中使用的是where子句设置查询条件的,于SQL不同的是HQL中使用的是对象的属性名字而不是数据库表中的属性名字。对于QBC则使用的是Criterion对象设置查询条件,通常使用Restrictions类创建Criterion对象。

Criteria.add(Restrictions.ge(“age”,20));

7.HQL中绑定参数

在实际查询中,用户输入一些查询条件,要求返回满足查询条件的记录。

有两种方式:一种是按照名称绑定,使用 :paramName 之后再后面使用query.setString(“paramName”,val);绑定参数值。

当然还提供了很多其他的类型,String Integer

另一种是按照参数的位置绑定,使用?来定义参数位置

String hql = “from Customer as c where c.reanName=?”;

query.setString(0, val);这里的位置是在0开始的,而JDBC中的PreparedStatement是在0开始的。

8.连接查询

HQL和SQL一样也是支持连接查询的,此外还有fetch预抓起内连接和fetch左外连接。

内连接 inner join or join

预抓起内连接: inner join fetch or join fetch

左外连接: left outer join or left join

预抓起左外连接: left outer join fetch or left join fetch

右外连接: right outer join or right join

内连接:inner join 默认使用join表示的就是inner join。只要两个持久化类关联字段之间有相符合的值,内连接就会组合两个表中的连接,常见于1-N的关联中

9.投影分组和统计

9.1投影

String hql = “select c.id, c.userName from Customer”;

List<Object[]> list = query.list();

如果是想反返回Customer对象的话,需要声明只有以上参数的构造函数,但是这样的话就会生成大量的Customer持久化对象保存在Session缓冲中。所以当数据量比较大的时候,最好不要使用这一种方式,下面我们介绍使用一种新的方式使用Map

String hql= “selecy new map(c.id, c.userName) from Customer as c”;

List<Map> list = query.list();

for(Map m : list){m.get(“0”); m.get(“1”)};

这一种方式的话,不会占用Session混村,只要程序中失去对他们的引用的时候,就会被JVM回收掉。所以当初局量比较大的时候,推荐是的实例化而不是持久化对象。

9.2HQL分组统计

count min max sum avg 函数都是可以在HQL中使用的函数

String hql = “slect count(c.id) from Customer as c ”;

Long count = (Long)session.createQuery(hql).uniqueResult();

String hql =”select max(c.avg), min (c.age) from Customer as c”

Object[] objs = (Object[]) session.createQuery(hql).uniqueResult();

Integer maxAge = (Integer)objs[0];

Integer maxAge = (Integer) objs[1];

分组查询

HQL中也会使用group by关键字进行分组查询,也可以使用having关键字对数据设定约束条件。

10.动态查询

Hibernate中查询数据的方式有两种:静态查询(在编写程序的时候就已经确定好需要查询的字段)和动态查询(在编写程序的时候不能够确定要查询的字段),所以一般情况下,HQL是和静态查询,而QBC适合动态查询。

HQL需要根据参数,动态的修改HQL语句,从而实现动态查询。

QBC如下:

public static List<Customer> findCustomersByCriteria(String name, Integer age){

Session session = HibernateUtil.getSession();

Criteria criteria = session.createCriteria(Customer.class);

if(name!= null){

criteria.add(Restrictions.ilike("userName", name));

}

if(age != null && age != 0){

criteria.add(Restrictions.eq("age", age));

}

return criteria.list();

}

11.子查询

form Customer as c where c.age = (select c1.age from Customer as c1 where c1.userName = :userName) and c.userName != :username

from Customer as c where 100>all(select o.total from c.orders o);

12.查询方式的比较

Hibernate最常使用的就HQL和QBC两种:

HQL和SQL比较接近,功能强大,支持各种查询,但是必须是提供局域字符串的查询,动态查询比较麻烦

QBC封装了个统一的API,编译期会检查,适合动态查询,但是可读性比较差

最后的一点内容就是关于Hibernate的事务管理机制:

Hibernate是JDBC轻量级的封装,本身是没有事务管理能力的,在事务管理层,Hibernate将其委托给底层的JDBC或者是JTA实现事务管理和调度。同时需要掌握好数据库的事务管理机制,才可以开发更加高效的并发Hibernate应用。

事务具有ACID四大性质,这些是由数据库管理系统实现的,对于事务的Isolation机制,数据库管理系统使用的是锁机制。实际开发中,事务的隔离性不完全,就会导致各种并发的问题:

更新丢失:两个事务同时更新一个数据的话,由于一个事务的撤销导致另一个事务对数据的修改液失效了

脏读:一个事务读取到另一个事务还没有提交但是已经更改过的数据,这种状态下,数据是不一致的

不可重复读:当一个事务读取了某些数据的时候,另一个事务修改了这个数据并且提交。当该事务再次读取这些数据的时候,数据已经被改变了;

幻读:同一个查询操作在一个事务中执行多次,但是因为其他的事物插入操作,这样导致每一次读取的数据都是不同的,称之为幻读。

所以为了避免这些并发问题的出现,保证数据的完整性和一致性,必须实现事务的隔离性。在事务执行的时候,是他们好像是系统在给定的时间内执行的唯一操作,如果这一个时刻会有两个事务同时执行,执行的功能相关,事务的隔离性会保证每一个事务在系统中认为只有该事务使用这个系统。

事务隔离性的标准:

序列化级别(Serializable)所有的事务都是相互隔离的,就不存在并发的情况了,隔离级别最高

可重复读(Repeatbale read):所有的被select获取的数据是不可以被修改的。

读已提交(Read committed):读取数据的事务允许其他事务访问器正在读取的数据,但是未提交的写事务将会禁止其他事务访问正在写的数据。

读未提交(Read uncommitted):如果一个事务已经开始写数据的话,则不允许其他的事务同时进行写操作,但是允许其他的事务读取器正在写的数据,这是事务隔离的最低级别。

在hibernate中配置属性 hibernate.connection.isolation = 4 也就是可重复读,默认是读已提交2.

Transaction trans = session.beginTransaction();

try{

session.save(customer);

}catch(Exception e){

Trans.rollback();

}

trans.commit();

HibernateUtil.closeSession();

YangTengfei

2013.11.29

Hibernate入门6.Hibernate检索方式的更多相关文章

  1. Hibernate基础学习(七)—检索方式

    一.概述      Hibernate有五种检索方式. 1.导航对象图检索方式      根据已经加载的对象,导航到其他对象. Order order = (Order)session.get(Ord ...

  2. Hibernate入门1. Hibernate基础知识入门

    Hibernate入门1. Hibernate基础知识入门 20131127 前言: 之前学习过Spring框架的知识,但是不要以为自己就可以说掌握了Spring框架了.这样一个庞大的Spring架构 ...

  3. Hibernate —— HQL、QBC检索方式

    一.HQL 检索方式 以双向的一对多来测试 HQL 检索方式.以 Department 和 Employee 为例. 建表语句: CREATE TABLE department ( dept_id ) ...

  4. Hibernate的三种常用检索方式

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

  5. java框架之Hibernate(4)-几种检索方式

    准备 模型及映射文件 package com.zze.bean; import java.util.HashSet; import java.util.Set; public class Class ...

  6. 总结hibernate框架的常用检索方式

    1.hibernate框架的检索方式有以下几种: OID检索:根据唯一标识OID检索数据 对象导航检索:根据某个对象导航查询与该对象关联的对象数据 HQL检索:通过query接口对象查询 QBC检索: ...

  7. Hibernate入门1 - Hibernate概述及第一个小例子

    一.什么是ORM? ORM,即Object Relational Mapping.我们知道,利用面向对象的思想编写的数据库应用程序最终都是把对象信息保存在关系型数据库中,于是需要编写与底层数据库相关的 ...

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

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

  9. Hibernate 检索方式

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

随机推荐

  1. linux 下搭建 storm

    搭建storm  需要搭建: 1.zookeeper 搭建 2.下载/安装 storm 的依赖包  zeromq, jzmq,python 2.storm 搭建 一.Zookeeper 安装 下载安装 ...

  2. ios开发 通讯录

    一.通信录开发 通信录开发主要是获取用户手机中的联系人 通过获取用户的通信录,可以在应用中添加好友等 二.如何访问用户的通讯录 在iOS9之前,有2个框架可以访问用户的通讯录 目前需要适配iOS8,所 ...

  3. Photoshop 使用曲线

    曲线表示的是图像的明度, 通过信息办的 HSB 信息可以看到调整曲线时整个图像明度的变化 曲线的左下角表示图片的暗部, 右下角表示图片的高光部 而曲线本身的纵坐标则表示这个部分的明度, 例如将曲线的左 ...

  4. 2d,3d中旋转推导

    二维绕原点旋转,其实点为(x,y),旋转角度为黄色标注的角度. 推导过程如下: x' = r cos(al+be); y' = r sin(al+be);x '= rcosalcosbe-rsinal ...

  5. iOS中POST异步请求

    POST异步请求(代理) 1.遵循<NSURLConnectionDataDelegate> @interface ViewController ()<NSURLConnection ...

  6. [Delphi编译错误]F2084 Internal Error: U2107

    看到这个错误真是头痛,这是一个很旧的项目了,想修改下东西,清理下工程一编译出现这个该死的错误,百度了下,也没解决问题.没办法只好编译所有的BPL了.   这个项目是带包编译的,而且带了几个自己的包. ...

  7. Practice:输入年月日,判断该时间为一年的第几天

    #-*- coding:utf- -*- ''' Created on -- # 输入年月日,判断为一年的第几天 @author: AdministrInputator ''' def leapYea ...

  8. javascript arguments与javascript函数重载

    1.所 有的函数都有属于自己的一个arguments对象,它包括了函所要调用的参数.他不是一个数组,如果用typeof arguments,返回的是’object’.虽然我们可以用调用数据的方法来调用 ...

  9. c#开发Mongo笔记第八篇

    到今天为止,Mongo开发的权限管理系统功能就做完了,剩下的就是完善构架,优化结构,只是现在c#操作Mongo的各种操作基本都掌握了 说到权限管理系统,其实再简单不过了,在关系型数据的是时代,我们通常 ...

  10. Python学习第八天(os)

    os主要是实现文件夹的创建和管理功能 os.mkdir(path) 创建目录 os.chdir(path)改变当前工作目录 os.fchdir() 通过文件描述符改变工作目录 os.chroot() ...