目录
一、HQL高级查询
之前我们已经介绍了简单的基本查询,条件查询和分页查询。
1.1 聚合查询
String hql = "select count(*) from Customer ";
String hql1 = "select max(id) from Customer ";
String hql2 = "select min(id) from Customer ";
String hql3 = "select sum(id) from Customer ";
String hql4 = "select avg(id) from Customer ";
Query query = session.createQuery(hql4);
Number result = (Number)query.uniqueResult();
1.2 投影查询
String hql = "select name from Customer ";
String hql1 = "select id,name from Customer ";
String hql2 = "select new Customer(id,name) from Customer ";
Query query = session.createQuery(hql2);
List<Customer> list = query.list();
hql 查询结果:
hql1 查询结果:
hql2 查询结果(这里需要提供一个类似的构造函数):
public Customer(int id,String name){
this.id = id;
this.name = name;
}
hql3 查询结果(这里需要提供一个无参构造函数):
public Customer(){
}
1.3 多表连接查询
连接查询的定义与分别
1.3.1 内连接
String hql = "from Customer c inner join c.linkMen";
Query query = session.createQuery(hql);
List<Object[]> list = query.list();
for (Object[] objects : list) {
System.out.println(Arrays.toString(objects));
}
输出
可以看出每个Object[] 数组中有两个元素,第一个元素Object[0] 是Customer对象,第二个元素Object[1]是LinkMan对象。
1.3.2 左连接
String hql = "from Customer c left join c.linkMen";
Query query = session.createQuery(hql);
List<Object[]> list = query.list();
for (Object[] objects : list) {
System.out.println(Arrays.toString(objects));
}
输出
删除了一个谷歌的联系人,但是客户表的所有数据都出来了,这就说明是左连接。
1.3.3 右连接
String hql = "from Customer c right join c.linkMen";
Query query = session.createQuery(hql);
List<Object[]> list = query.list();
for (Object[] objects : list) {
System.out.println(Arrays.toString(objects));
}
输出
二、Criteria查询
我们之前已经介绍了Criteria的查询,接下来介绍一些别的查询,因为Criteria查询必须要关联一个类,适合单表的查询,所以并不复杂。
2.1 排序查询
Criteria query = session.createCriteria(Customer.class);
query.addOrder(Order.desc("id"));
List<Customer> list = query.list();
System.out.println(list);
输出
2.2 聚合查询
Criteria query = session.createCriteria(Customer.class);
query.setProjection(Projections.avg("id"));
Number result = (Number)query.uniqueResult();
System.out.println(result);
输出
2.3 离线查询
非离线查询:
离线查询:
代码演示:
DetachedCriteria dc = DetachedCriteria.forClass(Customer.class);
dc.add(Restrictions.idEq(2));
Session session = HibernateUtils.getCurrentSession();
Transaction tx = session.beginTransaction();
Criteria query = dc.getExecutableCriteria(session);
List<Customer> list = query.list();
System.out.println(list);
tx.commit();
输出
三、查询优化
懒加载的和关联查询的使用。
3.1 类级别查询
get方法:没有任何的加载策略,调用即查询数据库加载数据。
load方法:应用类级别查询的加载策略
<class name="Customer" table="customer" lazy="true">
</class>
在配置文件中配置lazy="true"(默认值),就会使用懒加载策略,查询时会返回代理对象,会在使用属性时,根据关联的session查询。
lazy="false" 时,load和get方法是没有任何区别的,调用即加载数据。
结论:为了提高效率,建议使用延迟加载策略。
注意:使用懒加载时要确保,调用属性加载数据时,session还是打开的,不然会抛出异常。(和ef一样,dbcontext必须是同一个,且没有释放。)
3.2 关联级别查询
一对多加载集合策略
lazy属性: 决定是否延迟加载
true(默认值): 延迟加载,懒加载
false: 立即加载
extra: 极其懒惰
fetch属性: 决定加载策略.使用什么类型的sql语句加载集合数据
select(默认值): 单表查询加载
join: 使用多表查询加载集合
subselect:使用子查询加载集合
多对一的关联属性加载策略
fetch 决定加载的sql语句
select: 使用单表查询
join : 多表查询
lazy 决定加载时机
false: 立即加载
proxy: 由customer的类级别加载策略决定.
结论:为了提高效率,fetch的选择上应该选择select,lazy的取值应选择true。即全部使用默认值,不用管。
3.3 no-session的问题
当我们查询完一个对象时,如果在页面jsp使用其关联属性,一般的我们在service层就完成了查询,关闭了session,这时候再使用关联属性可能就会抛出异常。为了解决session范围的问题,我们可以扩大session的访问,在请求开始的时候打开session,在请求结束的时候关闭session。这和ef的当前请求一个上下文是一样的道理HttpContext.Current.Item["dbContext"] 一样的。
在java中我们使用Filter来拦截请求实现这个功能
四、总结
今天我们学习hibernate的高级查询内容,具体用的时候还要看情况使用。