精通hibernate学习笔记(8)[检索方式]
提供的检索方式:
(1)导航对象图检索方式
(2)OID检索方式
(3)HQL检索方式
(4)QBC检索方式[querybyCriteria(标准)]
(5)本地SQL检索方式
1、简介
1.1HQL检索方式
HQL(HibernatequeryLanguage)是面向对象的查询语言,在Hibernate提供的检索方式中,HQL是使用最广泛的检索方式。功能:
a.在查询语句中设定各种查询条件
b.支持投影查询,即仅检索出对象的部分属性
c.支持分页查询
d.支持连接查询
e.支持分组查询,允许使用having和groupby关键字
f.提供内聚聚集函数,如sum(),min()和max()
g.支持子查询,即嵌入式查询
h.支持动态帮定参数
session的find方法以及Query接口都是支持HQL检索方式的,这两者的区别在于,前者只是执行一些简单的HQL查询语句的便捷方式,它不具有动态邦定参数的功能,Query接口才是真正的HQL查询接口。
//创建一个Query对象
Queryquery=session.createQuery("fromCustomerascwherec.name=:customerNameandc.age=:customerAge");
//动态绑定参数
query.setString("customerName","Tom");
query.setInteger("customerAge",21);
//执行查询语句,返回结果
Listresult=query.list();
1.2QBC检索方式
QBC提供的查询方式由:Criteria接口,Criterion接口和Expression类组成,支持在运行时动态生成查询语句。
//创建一个Criteria对象
Criteriacriteria=session.ceateCriteria(Customer.class);
//设定查询条件,然后把查询条件加入到Criteria中
Criterioncriterion1=Exception.like("name","T%");
Criterioncriterion2=Exception.eq("age",newInteger(21));
criteria=criteria.add(criterion1);
criteria=criteria.add(criterion2);
//执行查询语句,返回查询结果
Listresult=criteria.list();
QBE(QuarybyExample)检索方式,是QBC的子功能。它允许先创建一个对象样板,然后检索出所有和这个样板相同的对象。
//创建一个Customer样板对象
Customerexample=newCustomer();
example.setAge(21);
Listresult=session.createCriteria(Customer.class)
.add(Example.create(example0)
.list();
1.3SQL检索方式
HQL和QBC检索时,Hibernate会生成标准的SQL查询语句,适用于所有的数据库平台,这两种方式都是跨平台的。
有的应用程序可能需要根据底层数据库的SQL方言,来生成一些特殊的查询语句,这样可以利用SQL查询方式。
Queryquery=session.createSQLQuery("select{c.*}fromCUSTOMERScwherec.NAMElike:customerNameandc.AGE=:customerAge","c",Customer.class);
query.setString("customerName","T%");
query.setInteger("customerAge",21);
Listresult=query.list();
1.4....
1.5适用别名
fromCustomerascwherec.name=:name
=fromCustomercwherec.name=:name
1.6多态查询
HQL和QBC都支持多态查询,多态查询是指查询出当前类及所有子类的实例,
session.createQuery("fromEmployee");orsession.createCriteria(Employee.class);
如果Employee类有两个子类:HourlyEmployee和SalariedEmployee,那么这个查询语句会查出所有的Employee实例,以及HourlyEmployee类和SalariedEmployee类的实例。
session.createQuery("fromHourlyEmployee");
session.createCriteria(HourlyEmployee.class);//只检索子类
1.7对查询结果排序
HQL采用orderby,QBC采用Order类对结果排序
//HQL
Queryquery=session.createQuery("fromCustomercorderbyc.name");
//QBC
Criteriacriteria=session.createCriteria(Customer.class);
criteria.addOrder(Order.asc("name"));
1.8分页查询
Query和Criteria接口都提供了用于分页显示查询结果的方法
a.setFirstResult(intfirstResult):开始索引位置(从0开始)
b.setMaxResult(intmaxResults):一次最多检索出的对象数目
1.9检索单个对象
Query和Criteria接口都提供了以下用于执行查询语句并返回查询结果的方法。
a.list方法:返回一个list类型的查询结果(setMaxResult(1)即返回单个对象)
b.uniqueResult()方法:返回单个对象
1.10在HQL查询语句中绑定参数
Hibernate参数机制依赖于JDBCAPI中的PreparedStatement的预定义SQL语句功能。优点:
a.非常安全,
b.能够利用底层数据库预编译SQL语句的功能,提高查询数据的性能。预编译是指底层数据库系统只需编译SQL语句一次,把编译出来的可执行代码保存在缓存中,如果多次执行相同形式的SQL语句,不需要重新编译,只需要从缓存中获得执行代码即可。(而如果使用条件拼sql会每次都重新编译。)
1.10.1参数绑定的形式
a.按照参数名字绑定,命名参数以":"开头。eg:c.name=:name
b.按照参数位置绑定,用?来定义参数的位置。eg:c.name=?
按名字绑定的优势:
a.使程序代码有较好的可读性
b.按名字绑定有利于程序代码的维护,而对于按位置绑定方式,如果参数在HQL查询语句中的位置改变了,就必须修改相关帮定参数的代码,这削弱了程序代码的健壮性和可维护性。
c.按名字绑定方式允许一个参数在HQL查询语句中出现多次。
1.10.2绑定各种类型的参数
a.setXxxxx(),如:setInteger();
b.三个特殊的参数绑定方法
-->setEntity():把参数与一个持久化类的实例绑定,主要是用其中的OID进行查询
session.createQuery("fromOrderowhereo.customer=:customer")
.setEntity("customer",customer)
.list();
对应的SQL:
select*fromORDERSwhereCUSTOMER_ID=1;
-->setParameter()方法:绑定任意类型的参数
query.setParameter("customer",customer,Hibernate.entity(Customer.class));
query.setParameter("orderNumber",orderNumber,HIbernate.STRING);
//某些类型Hibernate可以根据参数值的java类型推断出对应的映射类型,此时不需要显示指定一个摄类型
query.setParameter("orderNumber",orderNumber);
但是日期类型的一般要指定,因为有好几种可能
-->setProperties()方法:用于把命名参数与一个对象的属性值绑定
Customercustomer=newCustomer();
customer.setName("Tom");
customer.setAge(21);
Queryquery=session.createQuery("fromCustomerascwherec.name=:nameandc.age=:age");
query.setProperties(customer);
:name会和Customer对象的name属性匹配。
1.11在映射文件中定义命名查询语句
<hibernate-mapping>
<classname="mypack.Customer"table="CUSTOMERS">
...
</class>
<queryname="findCustomersByName"><![CDATA[
fromCustomercwherec.namelike:name
]]></query>
</hibernate-mapping>
<query>元素用于定义一个HQL查询语句,他和<class>元素并列,程序中使用方式:
Queryquery=session.getNameOfQuery("findCustomersByName");
query.setString("name",name);
Listresult=query.list();
<query>元素也可以用于定义一个本地SQL语句
2、设定查询条件
HQL查询通过where子句来设定查询条件,注意的是fromCustomercwherec.name='tom',注意的是,在where子句中给出的是对象的属性名,而不是字段名.
对于QBC查询,必须创建一个Criterion对象来设定查询条件,Expression类提供了创建Criterion实例的工厂方法。
2.1比较运算
2.2范围运算
in、between...and...、等
2.3字符串模式匹配
通配符:
%:匹配任意类型并且任意长度(可以=0)的字符串,如果是中文,需要两个百分号,即"%%"
_:匹配单个任意字符,常用来限制字符串的表达式长度。
2.4逻辑运算
3、连接查询
和SQL查询一样,HQL与QBC也支持各种各样的连接查询,如内连接、外连接和交叉连接,HQL和QBC还支持迫切内连接和迫切左外连接。
迫切左外连接和迫切内连接不仅指定了连接查询方式,而且显式指定了关联级别的检索策略。
3.1默认情况下关联级别的运行时检索策略
3.2迫切左外连接
----会采取迫切左外连接检索策略----
//HQL
Queryquery=session.createQuery("fromCustomercleftjoinfetchc.ordersowherec.namelike'T%'");
Listresult=query.list();
//QBC检索方式
Listresult=session.createCriteria(Customer.class)
.setFetchMode("orders",FetchMode.EAGER)
.add(Expression.like("name","T",MatchMode.START))
.list();
HQL:leftjoinfetch关键字表示迫切左外连接检索策略。
QBC:FetchMode.EAGER表示迫切左外连接检索策略。所有的orders集合都被初始化,且返回的Customer对象集合中可能有重复的元素,可以使用HashSet来过滤:
HashSetset=newHashSet(result);
3.3左外连接
//HQL
Queryquery=session.createQuery("fromCustomercleftjoinc.ordersowherec.namelike'T%'");
Listresult=query.list();
for(Iteratorpairs=result.iterator();pairs.hasNext();){
Object[]pars=(Object[])pairs.next();
Customercustomer=(Customer)pairs[0];
Orderorder=(Order)pairs[1];
}
根据映射文件来决定orders集合的检索策略
注:返回结果中与迫切左外连接的不同,迫切左外连接,返回customer,这里返回是对象数组(一行数据拆成了两个对象)
如果希望返回的集合中仅包含Customer对象,可以在HQL查询语句中使用select关键字:
session.createQuery("selectcfromCustomercleftjoinc.ordersowherec.namelike'T%'");
但初始化orders的时间由映射文件决定
3.4内连接
同样可以设定select关键字来使得之返回Customer对象。
QBC也支持内连接查询:
CriteriacustomerCriteria=session.createCriteria(Customer.class);
customerCriteria.add(Expression.like("name","T",MatchMode.START));
CriteriaorderCriteria=customerCriteria.create(Criteria("orders"));
orderCriteria.add(Expression.like("orderNumber","T",MatchMode.START));
Listresult=orderCriteria.list();
另:等价于
Listresult=session.createCriteria(Customer.class)
.createAlias("orders","o")
.add(Expression.like("this.name","T",MatchMode.START)//Customer的默认别名=this
.add(Expression.like("o.orderNumber","T",MatchMode.START))
.list();
默认情况下,QBC只检索出Customer对象,以上代码等价于H
===>selectcfromCustomercjoinc.ordersowherec.namelike'T%'ando.orderNumberlike'T%'
3.5迫切内连接
session.createQuery("fromCustomercinnerjoinfetchc.ordersowherec.namelike'T%'");
如果包含重复元素也可以用HashSet来过滤。
注:QBC不支持迫切内连接
3.6隐式内连接
HQL:
通过o.customer.name的形式访问与Order关联的Customer对象的name属性
fromOrderowhereo.customer.namelike'T%'
以上代码虽然没有使用join关键字,它隐式指明使用内连接查询,他和一下HQL查询语句等价:
fromOrderojoino.customercwherec.namelike'T%'
QBC:
不支持隐式内连接,必须显式指定
3.7右外连接
3.8使用SQL风格的交叉连接和隐式内连接
HQL支持SQL风格的交叉连接查询,eg:
fromCustomer,Order
这个SQL执行交叉连接查询,将返回CUSTOMERS表与ORDERS表的交叉组合。(n*m条结果)
HQL内连接查询语句:
fromCustomercinnerjoinc.orders;
如果Customer没有orders集合属性,可以采用SQL风格的隐式内连接查询语句:
fromCustomerc,Orderowherec.id=o.customer_id
3.9关联级别运行时的检索策略
总结:
(1)如果在HQL或QBC程序代码中没有显示指定检索策略,将使用映射文件配置的检索策略,但有个例外,即HQL总是忽略映射文件中设置的迫切左外连接检索策略。也就是说,及时映射文件中设置了迫切左外连接检索策略,如果HQL查询语句中没有显示指定这种策略,那么HQL仍然采用立即检索策略。
(2)如果在HQL或QBC程序代码中显示指定了检索策略,就会覆盖映射文件配置的检索策略。
在HQL查询语句中显示指定的检索策略包括以下内容:
a.leftjoinfetch
b.innerjoinfetch
QBC中FetchMode类的三个静态实例,指定检索策略
a.FetchMode.DEFAULT:默认值,采用映射文件中配置的检索策略。
b.FetchMode.EAGER:迫切左外连接
c.FetchMode.LAZY:显示指定延迟检索。(HQL中没有提供该功能)
(3)只允许在一个sql语句中迫切左连接检索一个集合(一对多或多对多关联),允许在一个查询语句中迫切左连接检索多个一对一关联或着多对一关联
(4)HQL支持的各种连接查询