本文内容总结自 孙卫琴 精通Hibernate 电子工业出版社
对象图导航查询、OID查询、HQL、QBC、本地SQL
1、HQL 检索方式
HQL 是 使用 hibernate 时使用最广的一种方式 功能如下
a、查询语句中设定各种查询条件
b、支持投影查询,即仅检索出对象的部分属性
c、支持分页查询
d、支持连接查询
e、支持分组查询,having和groupBy
f、提供内置聚集函数 sum、min、max
g、能调用用户定义的SQL函数或标准SQL函数
h、支持子查询
i、支持动态绑定参数
方法链编程风格
List result=session.createQuery("from Customer as c where c.name=:customerName and c.age=:customerAge")
.setString("customerName","tom");
.setInteger("customerAge",21);
.list();
2、QBC(query by criteria)
// Criteria criteria =session.createCtiteria(Customer.class);
List result=session.createCriteria(Customer.class).add(Restrictions.like("name","T%")).add(Restirictions.eq("age",21))
对结果集排序
HQL:sessio.createQuery("from Customer c order by c.name");
QBC: session.crateCriteria(Customer.class).addOrder(Order.asc("name"))
分页查询
HQL:session.createQuery(from Customer c order by c.name asc"); query.setFirstResult(0); query.setMaxResult(10);
QBC:sessiion.createCriteria(Customer.class).addOrder(Order.asc("name")).setFirstResult(0).setMaxResult(10).list();
在HQL中调用函数 from Customer c where size(c.orders)>3
检索不属于任何客户的订单
HQL: from Order o where O.customer is null
QBC: session.createCriteria(Order.class).add(Restrictions.isNull("customer"))
查询以T开头以m结尾的customer对象
HQL:"from Customer c were c.name like 'T%' and c.name like ‘%m"
连接查询
a、迫切左外链接
HQL:from Clazz c left join fetch c.students c where c.clazzId=1;
QBC: session.createQuery(Clazz.class).setFetchMode("students",FetchMode.JOIN).addRestrictions.eq("clazzId",1);
当使用迫切左外连接时,查询结果可能会包含重复元素,可以使用hashset去重
在关联级别,我们通常使用默认的 lazy=true,在得到对象同时要得到其属性的场景下,我们即需要使用迫切左外连接
b、右连接
from Clazz c left join c.students s where s.name like 'M%'
c、内连接
from Clazz c,Student s where s.name like 'M%' and s.clazzId=c.clazzId
迫切左/右连接,返回的是单个对象的多条记录,左/右连接返回的是Object[ ] 迫切连接下many方会完成初始化,非迫切下不初始化
如果迫切左/右外连接的one方确定为一条记录,那么可以使用uniqueResult()方法,会将重复的记录合并
报表查询
a、Long count=(Long)session.createQuery("select count(*) from tableName t").uniqueResult;
b、Double age=(Double)session.createQuery(select avg(c.age) from User u).uniqueResult;
c、Object[] os=(Object[])session.createQuery("select max(c.age),min(c.age) from User u")
d、Long long=(Long)session.createQuery("select count(distinct u.name) from User u").uniqueResult();
优化报表查询性能
当select 部分属性时,返回的是 关系数据,与session无关,可以被JVM回收,可以使用javabean封装数据
select new package.ClazzRow(c.id,c.name,s.name) from Clazz c , c.students s where s.name like 'M%';
(构造)
group by
a、Iterator it=session.createQuery("select s.gender ,count (s) from Student group by s.gender").list.iterator
while(it.hasNext){
Object [] obj=(Object [ ]) it.next;
String gender=(String)obj[0];
Long count=(Long)obj(1);
}
b、"select c.id,c.name,count(s) from Clazz c left join c.studnets s group by c.id"
c、"select c.id,c.name,sum(s.age) from Clazz c left join c.students s group by c.id"
查询技巧
集合过滤
经常遇到的场景时,先加载了oneToMany的one方,再加载many,而加载many时又需要加条件,这时可以使用集合过滤,传入的集合 处于hibernate4种状态那种无所谓,
但其所属对象必须是持久状态,
a 、List result=session.createFilter(clazz.getStudents(),"where this.name like ‘M%’" orderBy this.age).list();
Iterator it=result.iterator();
while(it.hasNext){
Student s=(Student)it.next();
}
b、利用集合过滤器分页
List result=session.createFilter(customer.getOrders(),"order by this.price asc").setFirstResult(10).setMaxResult(50).list();
c、检索数据库中与customer对象的orders集合中order对象的订单编号
List result=session.createFilter(customer.getOrders,"select this.orderNum").list;
d、检索与Customer对象的orders集合中order对象价格相同的所有对象
List result=session.crateFilter(customer.getOrders,"select other from Order other where other.price=this.price").list();
e、假定order与lineitem(商品信息)一对多,Lineitem与item(商品)1对1,得到order的item
List result=session.createFilter(order.getLineItems(),"select this.item").list();
子查询
a、查询有1条以上订单的客户
from Customer c where 1<(select count(o) from c.orders o);
b、查询订单价格大于平均价格的订单
from Order o where o.price >(select avg(o1.price) from Order o)
c、子查询关键字
所有订单价格<100 from Customer c where 100>all (select o.price from c.orders o)
有一个订单价格<100 from Customer c where 100> any (select o.price from c.orders o)
有一个订单价格=10 from Customer c where 100 in (select o.price from c.order o)
HQL 集合函数 size()、minIndex() maxIndex() minElement(0 maxElement elements() ...
查订单数大于0的客户 from Customer c where c.orders.size >0 OR from Customer c where size(c.orders)>0
查询结果转换器 Criteria.ROOT_ENTITY,criteria.DIStINCT_ROOT_ENTITY, criteria.ALIAS_TO_ENTITY_MAP
a、确保查询结果不包含重复实例 (也可以通过使用hashset去重)
session.createCriteria(Customer.class).setFetchMode("orders",FetchMode.JOIN).setResultTransFormer(Criteria.DISTINCT_ROOT_ENTITY).list()
b、确保查询结果中包含根节点的实例及被关联的实例
session.createCriteria(Customer.class).createAlias("orders","o").setResultTransformer(Criteria.ALIAS_TO_ENTITY_MAP).list();
Iterator it=result.iterator();
while(it.hasNext()){
Map map=(Map)it.next();
Customer customer=(Customer)map.get(Criteria.ROOT_ALIAS);
Order order=(Order)map.get("o");
}
查询性能优化
1、降低访问数据库的频率、减少select 语句数目
a、使用迫切左外连接或迫切内连接
b、对延迟检索或立即检索策略设置批量检索数目
c、使用查询缓存
2、避免多余加载程序不许要访问的数据
a、使用延迟检索策略
b、使用集合过滤
3、避免报表查询占用缓存。利用投影查询,查询实体的部分属性
4、减少select 语句中的字段,从而将提访问数据库的数据量。(query的iterate())
A、session.createQuery(from Customer c).list();
query2=session.createQuery(from Customer c where c.age>30).iterate();
iterate()首先检索ID,然后根据ID到hibernate的1、2级缓存中找匹配的Customer对象,如果存在,就将其加入查询结果集,否则就执行额外的select语句,根据ID到数据库检索对象
5、查询缓存
如果查询结果中包含实体,查询缓存只会存放实体的OID,投影查询(select new Constructo(...) from),会缓存所有的数据
查询缓存适用场合:1、经常使用的查询语句 。2、很少对与查询语句检索到的数据进行插入删除或更新操作
对查询语句启用查询缓存的步骤
a、配置2级缓存
b、在hibernate.properties中 hibernate.cache_query_cache=true
c、session.createQuery(HQL).setCacheable(true);
3、本地SQL
有的应用可能需要根据底层数据库的SQL方言生成一些特殊的查询,这时使用本地SQL
Query query=session.createSQLQuery("select * from USERS where USERNAME like :userName");
4、OID
5、对象图导航