Hibernate的检索方式详解
Hibernate提供以下几种检索对象的方式。
l 导航对象图检索方式。(根据已经加载的对象,导航到其他对象。)
2 OID检索方式。(按照对象的OID来检索对象。)
3 HQL检索方式。(使用面向对象的HQL查询语言。)
4 QBC检索方式。(使用QBC(Qurey By Criteria) API来检索对象。)
5 本地SQL检索方式。(使用本地数据库的SQL查询语句。)
一、Hibernate的检索方式简介
1、HQL检索方式
HQL(Hibernate Query Language)是面向对象的查询语言,它和SQL查询语言有些相识。在Hibernate提供的各种检索方式中,HQL是使用最广的一种检索方式。它具有以下功能:
l 在查询语句中设定各种查询条件。
l 支持投影查询,即仅检索出对象的部分属性。
l 支持分页查询。
l 支持分组查询,允许使用having和group by关键字。
l 提供内置聚集函数,如sum()、min()和mac()。
l 能够调用用户定义的SQL函数。
l 支持子查询,即嵌入式查询。
l 支持动态绑定参数。
Session类的find方法及Qurey接口都支持HQL检索方式。区别在于,前者只是执行一些简单HQL查询语句的便捷方法,它不具有动态绑定参数的功能,而且在将来新的Hibernate版本中,有可能淘汰find方法;而Qurey接口才是真正的HQL查询接口,它提供了以上列出的各种查询功能。
注:Qurey接口支持方法链编程风格,它的set方法都返回自身实例,而不是返回void类型。方法链编程风格能使程序代码更加简洁。
示例代码:
Query query = session.createQuery("from Customer as c where c.name=:customerName and c.age=:customerAge"); // 动态绑定参数 query.setString("customerName", "Test");
query.setInteger("customerAge", 21);
// 执行检索 List result = query.list();
// 方法链编程风格
List result1 = session.createQuery("from Customer as c where c.name=:customerName and c.age=:customerAge").setString("customerName", "Test").setInteger("customerAge", 21) .list();
2、QBC(Qurey By Criteria)检索方式
采用HQL检索方式时,在应用程序中需要定义基于字符串形式的HQL查询语句。QBC API提供了检索对象的另一种方式,它主要由Criteria接口、Criterion接口和Expression类组成,它支持在运行时动态生成查询语句。
示例代码:
Criteria criteria = session.createCriteria(Customer.class);
Criterion criterion1 = Expression.like("namr", "T%");
Criterion criterion2 = Expression.eq("age", new Integer(21));
criteria = criteria.add(criterion1);
criteria = criteria.add(criterion2);
// 执行检索 List result = criteria.list();
// 方法链编程风格
List result1 = session.createCriteria(Customer.class).add(Expression.like("namr", "T%")).add(Expression.eq("age", new Integer(21))).list();
Hibernate还提供了QBE(Qurey By Example)检索方式,它是QBC的子功能。QBE允许先创建一个随想模板,然后检索出和这个样板相同的对象。
示例代码:
Customer exampleCustomer=new Customer(); exampleCustomer.setAge(21);
List result1 = session.createCriteria(Customer.class).add( Example.create(exampleCustomer)).list();
QBE的功能不是特别强大,仅在某些场合下有用。一个典型的使用场合就是在查询窗口中让用户输入一系列的查询条件,然后返回匹配的对象。QBE只支持“”和“”比较运算符,无法不大区间值,及其或的匹配。在这种情况下,还是采用HQL检索方式或QBC检索方式。
3、SQL检索方式
采用HQL或QBC检索方式时,Hibernate生成标准的SQL查询语句,使用于所有的数据库平台,因此这两种检索方式都是跨平台的
有的应用程序可能需要根据底层数据库的SQL方言,来生成一些特殊的查询语句。在这种情况下,可以利用Hibernate提供的SQL检索方式。
示例代码:
Query query = session.createSQLQuery("select {c.*} from CUSTOMER as c where c.NAME like :customerName and c.AGE=:customerAge");
query.setString("customerName", "Test");
query.setInteger("customerAge", 21); // 执行检索
List result = query.list();
4、使用别名
通过HQL检索一个类时,如果查询语句的其他地方需要引用它,应该为这个类指定一个别名,as关键字用于设定别名,也可以将as关键字省略。
QBC检索不需要由应用程序显式指定类的别名,Hibernate会自动把查询语句中的跟结点实体赋予别名“this”。
5、多态查询
HQL和QBC都支持多态查询,多态查询是指查询出当前类及所有子类的实例。多态查询对接口也使用。Hibernate不仅对from子句显式指定的类进行多态查询,而且对其他关联的类也会进行多态查询。
6、对查询结果排序
HQL和QBC都支持对查询结果进行排序。
query = session.createQuery("from Customer as c order by c.name"); //排序
criteria.addOrder(Order.asc("name"));
criteria.addOrder(Order.desc("age"));
7、分页查询
Query和Criteria接口都提供了用于分页显式查询结果的方法。
l setFirstResult(int firstResult):设置从那个对象开始检索,参数表示这个对象在查询结果中的索引位置,索引位置的起始值为0。默认从0检索。
2 setMaxResult(int maxResults):设置一次最多检索出的对象数目。默认检索所有。
示例代码:
criteria = criteria.add(criterion1);
criteria = criteria.add(criterion2);
criteria.setFirstResult(0);
criteria.setMaxResults(10); // 执行检索
List result = criteria.list();
query.setString("customerName", "Test");
query.setInteger("customerAge", 21);
query.setFirstResult(0);
query.setMaxResults(10); // 执行检索
List result = query.list();
8、检索单个对象
Query和Criteria接口都提供了以下用于查询语句并返回查询结果的方法。
l list()方法:返回一个List类型的查询结果。
l uniqueResult()方法:返回单个对象。
注:Query接口还提供了一个iterate()方法,它和list()方法一样,能返回所有满足条件的持久化对象,但是两者使用不同的SQL查询语句。
示例代码:
// 单个检索
Customer customer = (Customer) session.createQuery("from Customer as c order by c.name").setMaxResults(1) .uniqueResult(); // 单个检索
Customer customer = (Customer) session.createCriteria(
Customer.class).setMaxResults(1).uniqueResult();
如果明明知道一个对象,可以不调用setMaxResults(1)方法。
9、在HQL查询语句中绑定参数
A、按参数名字绑定。咋HQL中定义命名参数以“:”开头。
B、按照参数位置绑定。在HQL查询语句中用“?”来定义参数的位置。
示例代码:
Query query = session.createQuery("from Customer as c where " + "c.name=? and c.age=?");
// 动态绑定参数 query.setString(0, "Test");
query.setInteger(1, 21);
除了以上用于绑定映射类型的参数的方法,Hibernate还提供了以下三个特殊的参数绑定方法。
(1)setEntity()方法:把参数与一个持久化类的实例绑定。(用id关联)
(2)setParameter()方法:绑定任意类型的参数。
(3)setProperties()方法:用于把命名参数与一个对象的属性值绑定。
10、在映射文件中定义命名查询语句(略)
二.设定查询条件
在where子句中给出的是对象的属性名,而不是字段名。
HQL和QBC支持的各种运算
运算类型
HQL运算符
QBC运算符
含义
比较运算
=
Expression.eq()
等于
<>
Expression.not(Expression.eq())
不等于
>
Expression.gt()
大于
>=
Expression.ge()
大于等于
<
Expression.lt()
小于
<=
Expression.le()
小于等于
is null
Expression.isNull()
等于空值
is not null
Expression.isNotNull()
非空值
范围运算
in (列表)
Expression.in()
等于列表中的某一个值
not in (列表)
Expression.not(Expression.in())
不等于列表中的任意一个值
between 值1 and 值2
Expression.between()
大于等于值1并且小于等于值2
not between 值1 and 值2
Expression.not(Expression.between())
小于值1或者大于值2
字符串模式匹配
like
Expression.like()
字符串模式匹配
逻辑运算
and
Expression.add()或者Expression.conjunction()
逻辑与
or
Expression.or()或者Expression.disjunction()
逻辑或
not
Expression.not()
逻辑非
1、比较运算
(1)不区分大小写:HQL使用lower()或者 upper()来实现(如:”…lower(c.name)=’tom’”);
QBC使用.ignoreCase()来实现(如:Expression.eq(“”,””) .ignoreCase())。
注:在HQL中,可以调用SQL函数。lower()转小写,upper()转大写。
QBC不支持直接调用SQL函数。
(2)HQL查询支持数学运算表达式,而QBC不支持。
2、范围运算
HQL中的in示例: c.name in (‘aa’,’bb’);
QBC中的in示例: String[] names={‘aa’,’bb’}; Expression.in(‘name’,names); 。
3、字符串模式匹配
HQL和QBC通用:字符串模式中的通配符
通配符名称
通配符
作用
百分号
%
匹配任意类型且任意长度(长度可以为0)的字符串,如果是中文,需要两个百分号,即“%%”
下划线
_
匹配单个任意字符,常用来限制字符串表达式的长度
QBC:MatchMode类包含的各个静态常量实例
匹配模式
举例
MatchMode.START
Expression.like(“name”,”y”, MatchMode.START)
姓名以y开头
MatchMode.END
Expression.like(“name”,”y”, MatchMode. END)
姓名以y结尾
MatchMode.ANYWHERE
Expression.like(“name”,”y”, MatchMode. ANYWHERE)
姓名中包含y
MatchMode.EXACT
Expression.like(“name”,”y”, MatchMode. EXACT)
精确匹配,姓名必须为y
4、逻辑运算
三、连接查询
HQL和QBC支持的各种连接类型
在程序中指定的链接查询类型
HQL语法
QBC语法
使用范围
内连接
inner join 或者 join
Criteria.createAlias()
适用于有关联的持久化类,并且在映射文件中对这种关联关系作了映射。
迫切内连接
inner join fetch 或者 join fetch
不支持
隐式内连接
不支持
左外连接
left outer join 或者 left join
不支持
迫切左外连接
left outer join fetch 或者 left join fetch
FetchMode.EAGER
右外连接
right outer join 或者 right join
不支持
交叉连接
ClassA,ClassB
不支持
适用于不存在关联关系的持久化类
1、默认情况下关联级别的运行时检索策略
采用配置文件中设置的检索策略,但有一个例外,那就是HQL会忽略映射文件设置的迫切左外连接策略,改用立即检索。
2、迫切左外连接
显式指定对象的关联关系为迫切左外连接检索策略,可以覆盖映射文件中指定的检索策略。
例HQL
"from Customer c left join fetch c.orders o where c.name like 't%'"
+" o.name like 't%'"
例QBC
List reslut=session.createCriteria(Customer.class) .setFetchMode("orders",FetchMode.EAGER) .add(Expression.like("name","t",MatchMode.START)) .list();
当使用迫切左外连接检索策略时,查询结果中可能会包含重复元素,可以通过一个HashSet来过滤重复元素:List result=….list(); HashSet set=new HashSet(result);
Hibernate允许在一条查询语句中迫切左外连接多个多对一或一对一关联的类。
List reslut=session.createCriteria(A.class).setFetchMode("this.b",FetchMode.EAGER) .setFetchMode("this.c",FetchMode.EAGER) .add(Expression.isNotNull("this.b")) .add(Expression.isNotNull("this.c")) .list();
当存在传递关联时,可以通过HQL来同时迫切左外连接关联类和依赖关联类,但QBC无法表达这种形式的迫切左外连接。
3、左外连接
使用左外连接查询时,将根据映射文件的配置来决定关联的检索策略。
4、内连接
QBC也支持内连接查询
List reslut=session.createCriteria(Customer.class).add(Expression.like("name","t",MatchMode.SRART)).createCriteria("orders").add(Expression.like("orderNumber","t",MatchMode.SRART)) .list();
默认情况下,QBC只检索出Customer对象,以上代码等同于以下HQL查询语句:
"select c from Customer c join c.orders o where c.name like 't%'"
+ " and o.orderNumber like 't%'";
createAlias()方法为关联属性(集合)赋予别名。如果希望QBC返回的集合也包含成对的Customer和Order对象,可以调用returnMaps()方法:
List reslut=session.createCriteria(Customer.class).createAlias("orders","o").add(Expression.like("this.name","t",MatchMode.SRART)).add(Expression.like("o.orderNumber","t",MatchMode.SRART)) .returnMaps() .list();
采用内连接查询时,HQL与QBC有不同的默认行为,前者检索成对的对象,后者仅检索出要检索的单个对象(不包含关联的对象)。
5、迫切内连接
显式指定对象的关联关系为迫切内连接检索策略,可以覆盖映射文件中指定的检索策略。
6、隐式内连接
一对一
"from Cunstomer c where c.homeAddress.provice like '%hai%'"
List reslut=session.createCriteria(Customer.class) .add(Expression.like("homeAddress.provice","t",MatchMode.SRART)) .list();
多对一
"from Order o where o.customer.name like '%hai%'"
QBC 不支持隐式内连接,下边是不正确的,:
List reslut=session.createCriteria(Order.class).add(Expression.like("customer.name","t",MatchMode.SRART)) .list();
对于QBC,必须显式指定内连接查询:
List reslut=session.createCriteria(Order.class).createAlias("customer","c").add(Expression.like("c.name","t",MatchMode.SRART))
.list();
一对多或多对多
隐式内连接不适用。
7、右外连接
8、使用SQL风格的交叉连接和隐式内连接
HQL支持SQL风格的交叉连接查询。如: from Customer c, Order o
在SQL语言中,显式内连接查询的语句使用inner join关键字,并且用on字句设定连接条件,形式为:
"select * from CUSTOMER c inner join ORDER o on c.ID=o.CUSTOMER_ID"
隐式内连接查询语句不包含关键字阿,并且用where字句设定连接条件:
"select * from CUSTOMER c ,ORDER o where c.ID=o.CUSTOMER_ID"
9、关联级别运行是的检索策略
(1)没有显式指定,使用配置文件的,但有一个例外,那就是HQL会忽略映射文件设置的迫切左外连接策略,改用立即检索。
(2)如果显式指定,就会覆盖映射文件配置的检索策略。在HQL查询语句中显式指定检索策略包括以下内容。
l left join fetch
l inner join fetch
QBC通过FetchMode类来显式指定检索策略,有以下3个静态实例。
l FetchMode.DEFAULT:默认,采用配置;
l FetchMode.EAGER:覆盖,指定迫切左外连接检索策略;
l FetchMode.LAZY:覆盖映射配置文件的检索策略,在程序中指定延迟检索策略。