Hibernate(3)——HQL

1 HQL

HQL(Hibernate Query Language) 是面向对象的查询语言, 它和 SQL 查询语言有些相似. 在 Hibernate 提供的各种检索方式中, HQL 是使用最广的一种检索方式. 它有如下功能:

  • 在查询语句中设定各种查询条件;
  • 支持投影查询, 即仅检索出对象的部分属性;
  • 支持分页查询;
  • 支持连接查询;
  • 支持分组查询, 允许使用 HAVING 和 GROUP BY 关键字;
  • 提供内置聚集函数, 如 sum(), min() 和 max();
  • 支持子查询;
  • 支持动态绑定参数;
  • 能够调用 用户定义的 SQL 函数或标准的 SQL 函数。

HQL 查询包括以下步骤:

  1. 获取Hibernate Session对象;
Configuration cfg = new Configuration();
SessionFactory sessionFactory = cfg.buildSessionFactory();
Session session = sessionFactory.getCurrentSession();
  1. 编写HQL语句;
  2. 以HQL语句作为参数,调用Session的createQuery方法创建查询对象;session.createQuery(hql);
  3. 如果HQL语句包含参数,则调用Query的setXxx方法为参数赋值;
  4. 调用Query对象的list()或uniqueResult()方法返回查询结果列表(持久化实体集)Qurey 接口支持方法链编程风格, 它的 setXxx() 方法返回自身实例, 而不是 void 类型,因此可以写类与.setXxx().setXxx().setXxx()…样式的语句。

1.1 使用

参考W3Cschool教程:
https://www.w3cschool.cn/hibernate_articles/gapw1ioo.html

1.2.1 在HQL语句中绑定参数

方法一:按参数位置绑定

Query q = HibernateSessionFactory.getSession().createQuery("from User u where u.name like =?");
q.setParameter(0, "");

方法二:按参数名字绑定

Query q = HibernateSessionFactory.getSession().createQuery("from User u where u.name like :name");
q.setParameter("name", "");
setProperties(可以为对象和集合)

最简单实体查询例子:

String hql = "from User";
Query query = session.createQuery(hql);
List<User> list = query.list();
System.out.println(list);

需要的数据可能仅仅是实体对象的某个属性(库表记录中的某个字段信息):

/** String hql = "SELECT user.name FROM User user";
List list = session.createQuery(hql).list();
Iterator it = list.iterator();
while(it.hasNext()){
    System.out.println(it.next());
}  */
public void test() {
    String hql = "SELECT user.name,user.age FROM User user";
    List list = session.createQuery(hql).list();
    Iterator it = list.iterator();
    while(it.hasNext()){
        Object[] results = (Object[]) it.next();
        System.out.println(results[0]+","+results[1]);
    }
}
// 通过在HQL中动态的构造对象实例的方法对这些平面化的数据进行封装
String hql = "SELECT new User(user.uName,user.uAge) FROM User user";
        List list = session.createQuery(hql).list();
        Iterator it = list.iterator();
        while(it.hasNext()){
            User user = (User) it.next();
            System.out.println(user);
        }
1.1.2 动态查询
String hql="from Users u where u.name=? and u.password=? ";
session.createQuery(hql).setParameter(0, "小明").setParameter(1, "123456");
public List<User> findUser2(Object[] obj) {
Query q = HibernateSessionFactory.getSession().createQuery(
"from User u where u.name like ?");
for (int i = 0; i < obj.length; i++) {
q.setParameter(i, obj[i]);
}
return q.list();
}

将每条查询结果封装成Object对象
String sql=“select u.name from User u”;
将每条查询结果封装成Object数组
String sql=“select u.name,u.id from User u”;
将每条查询结果通过构造函数封装成对象
String sql=“select new login(u.name,u.passwoord) from User u”;

1.1.3 分页查询

Query接口提供2个方法用于对查询结果分页:
setFirstResult((pageNow-1)*pageSize) : 从第?行开始提取(跳过几行)
setMaxResults(pageSize) : 要提取?行
在这里插入图片描述

1.1.4 hql和sql的区别

hql是面向对象的 。其实还是转成了sql语句,hql在数据库通用,切换数据库方言就可以;
sql在不同数据库中语法有些不同,还是sql比较灵活一些。。
HQL(Hibernate Query Language)查询提供了更加丰富的和灵活的查询特性,因此Hibernate将HQL查询方式立为官方推荐的标准查询方式,HQL查询在涵盖 Criteria查询的所有功能的前提下,提供了类似标准SQL语句的查询方式,同时也提供了更加面向对象的封装。
sql只是结构化查询语言,只是面向数据检索,不具有面向对象的特征,所以HQL更加符合开发标准!

1、sql 面向数据库表查询。
2、hql 面向对象查询。
3、hql : from 后面跟的 类名+类对象 where 后 用 对象的属性做条件。
4、sql: from 后面跟的是表名 where 后 用表中字段做条件查询。
5、在Hibernate中使用查询时,一般使用Hql查询语句。
6、HQL(Hibernate Query Language),即Hibernate的查询语言跟SQL非常相像。不过HQL与SQL的最根本的区别,就是它是面向对象的。

在Hibernate中使用查询时,一般使用Hql查询语句。
HQL(Hibernate Query Language),即Hibernate的查询语言跟SQL非常相像。不过HQL与SQL的最根本的区别,就是它是面向对象的。
使用HQL时需要注意以下几点:
a. 大小写敏感:
因为HQL是面向对象的,而对象类的名称和属性都是大小写敏感的,所以HQL是大小写敏感的。
HQL语句:from Cat as cat where cat.id > 1;与from Cat as cat where cat.ID > 1;是不一样的,这点与SQL不同。
b. from子句
from Cat,该句返回Cat对象实例,开发人员也可以给其加上别名,eg. from Cat as cat,对于多表查询的情况,可参考如下:from Cat as cat, Dog as dog

1.2 HQL迫切左外连接

LEFT JOIN FETCH关键字表示使用迫切左外连接策略:

String hql = "SELECT DISTINCT d FROM Department d LEFT JOIN FETCH d.emps";
Query query = session.createQuery(hql);
List<Department> depts = query.list();
System.out.println(depts.size());
for (Department dept : depts) {
    System.out.println(dept.getName() + "-" + dept.getEmps().size());
}

案例分析:

@Test
public void test1(){
	Map<String,Object> map = new HashMap<>();
	map.put("staffId",1);
	// 关联查询 关联的是属性查询
	String  hql=" from Staff s lef join s.department where s.staffId=:staffId";
	List<Object[]> list = session.createQuery(hql).setProperties(map).list();
	//包含两个对象  0:Staff   1:department
	System.out.println(Arrays.toString(list.get(0)));
}
@Test
public void test2() {
	Map<String,Object> map = new HashMap<>();
	map.put("staffId",1);
	// 关联查询 关联的是属性查询  fetch 迫切  想要把关联对象封装到该对象的属性里面
	String hql = " from Staff s left join fetch s.department ";
	// Staff 里面的属性 department是有值的
	List<Staff> list = session.createQuery(hql).setProperties(map).list();
	for (Staff s : list) {
	System.out.println(s.getDepartment());
	}
}

1.3 查询缓存

首先需要明白什么是缓存?
**缓存:**指数据存放的一种方式,把数据存储在内存中,当需要获取数据时,直接从缓存中获取,这样可以提升执行效率。

hibernate提供查询缓存,用于减轻数据压力,提高数据库性能。
经常做查询,修改比较少,而且不需要事时显示的数据,甚至能允许一部分过期数据存在,这样才使用查询缓存.

Session的缓存有三大作用:
1.减少访问数据库的频率。应用程序从缓存中读取持久化对象的速度显然比到数据中查询数据的速度快多了,因此Session的缓存可以提高数据访问的性能。
2.当缓存中的持久化对象之间存在循环关联关系时,Session会保证不出现访问对象图的死循环,以及由死循环引起的JVM堆栈溢出异常。
3.保证数据库中的相关记录与缓存中的相应对象保持同步。

hibernate提供一级缓存,二级缓存:
一级缓存是Session级别的缓存。在操作数据库时需要构造Session对象,在对象中有一个数据结构(HashMap)用于存储缓存数据。不同的Session之间的缓存数据区域(HashMap)是互相不影响的。

二级缓存是SessionFactory级别的缓存,多个Session对象共享同一个二级Cache。二级Cache的内部如何实现并不重要,重要的是采用哪种正确的缓存策略,以及采用哪个Cache提供器。二级缓存是跨Session的。

hql缓存是查询缓存,针对于hql的查询功能,hql默认查询出的对象不会被缓存,hql缓存的配置是依赖于二级缓存的。

1.3.1 一级缓存

Hibernate默认是开启一级缓存的,一级缓存存放在session上,属于事务级数据缓冲。

一级缓存的生命周期与session生命周期绑定,随session生命周期存在而存在,随session消亡而丢失。所以在session中get获取的数据,在session没有关闭前,再次get相同数据时,会发现hibernate不会再次查询数据库,而是直接获取到数据,如果关闭session之后,再次get,hibernate会重新查询。

测试一级缓存:首先执行get查询,然后再执行一次相同的get查询,不会再次执行sql,但是当关闭session之后,再执行get,那么又会执行查询。

PS:如果基于HQL并且查询的是部分字段,没有返回对象时,一级缓存不会保存这些数据,因为一级缓存只保留持久化对象。

  1. 在查询的时候,每次都是先去session容器中找是否有需要的对象,如果有,直接返回,这时候因为没有与数据库交互,不会发sql语句;
    如果session容器中没有,session向数据库查询,这时候会发出sql语句,查询返回了对象,也会放入session中一份,只要是持久状态,session就关联。
    哪些方法可以完成持久状态?
    get,load,save….
    当调用clear,evict,close的方法的时候,session容器都会清除对象,变成游离状态,为了避免脏数据
  2. 配置
    一级缓存不需要配置,默认已经实现
  3. 应用场景
service{
	//开始执行时,开启事务,获取Session对象
	//第一次调用方法findUserById(id)
	
	//第二次调用方法findUserById(id),从一级缓存中取数据
	//方法结束,Session关闭
}

如果是执行两次service调用查询相同 的用户信息,不走一级缓存,因为session方法结束,Session就关闭,一级缓存就清空。

1.3.2 二级缓存

二级缓存生命周期与sessionfactory生命周期绑定,hibernate自身没有二级缓存驱动支持,需要加载第三方jar包(下载插件)。
二级缓存是在SessionFactory,所有的Session共享同一个二级Cache。二级Cache的内部如何实现并不重要,重要的是采用哪种正确的缓存策略,以及采用哪个Cache提供器。

hibernate整合ehcache实现二级缓存

ehcache是一个分布式缓存框架

a. 分布式缓存

系统为了提高系统并发,性能、一般对系统进行分布式部署(集群部署方式)
不使用分布缓存,缓存的数据在各各服务单独存储,不方便系统 开发。所以要使用分布式缓存对缓存数据进行集中管理。
hibernate无法实现分布式缓存,需要和其它分布式缓存框架进行整合。
在这里插入图片描述

b. hibernate和ehcache整合步骤

hibernate提供了一个缓存接口,如果要实现自己的缓存逻辑,实现缓存接口开发即可。
hibernate和ehcache整合,hibernate和ehcache整合包中提供了一个cache接口的实现类。
配置如下:

  1. 导入包(下载依赖)
    ehcache-core ; hibernate-ehcache ; slf4j-api
  2. 根目录下添加ehcache的配置文件
  3. hibernate.cfg.xml启动二级缓存,实现类
<!-- 开启二级缓存 -->
<property name="cache.use_second_level_cache">true</property>
<!-- 实现类 -->
<property name="hibernate.cache.region.factory_class">
    org.hibernate.cache.ehcache.internal.EhCacheRegionFactory
</property>
  1. 设置哪些类的对象需要缓存,在hbm.xml中配置在这里插入图片描述
c. 二级缓存应用场景

对于访问多的查询请求且用户对查询结果实时性要求不高,此时可采用hibernate二级缓存技术降低数据库访问量,提高访问速度,业务场景比如:耗时较高的统计分析sql、电话账单查询sql等。

hql缓存 --> hibernate.cfg.xml 配置启动hql缓存 实现类 --> 查询的时候缓存hql setCacheable

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值