数据层的访问效率优化可能第一想到的就是利用缓存,缓存的机能可以简单理解为将从数据库中访问的数据放在内存中,在以后再次使用到这些数据时可以直接从内存中读取而不必要再次访问数据库,尽量减少和数据库的交互提高性能,在hibernate中提供了二种缓存机制:一级缓存、二级缓存,因为二级缓存策略是针对于ID查询的缓存策略,对于条件查询则毫无作用,为此,Hibernate提供了针对条件查询的Query Cache(查询缓存).....

(一)、一级缓存:

一级缓存是hibernate自带的,不受用户干预,其生命周期和session的生命周期一致,当前session一旦关闭,一级缓存就会消失,因此,一级缓存也叫session缓存或者事务级缓存,一级缓存只存储实体对象,不会缓存一般的对象属性,即:当获得对象后,就将该对象缓存起来,如果在同一个session中再去获取这个对象时,它会先判断缓存中有没有这个对象的ID,如果有,就直接从缓存中取出,否则,则去访问数据库,取了以后同时会将这个对象缓存起来。

(二)、二级缓存:

二级缓存也称为进程缓存或者sessionFactory级的缓存,它可以被所有的session共享,二级缓存的生命周期和sessionFactory的生命周期一致,二级缓存也是只存储实体对象。二级缓存的一般过程如下:

①:条件查询的时候,获取查询到的实体对象

②:把获得到的所有数据对象根据ID放到二级缓存中

③:当Hibernate根据ID访问数据对象时,首先从sesison的一级缓存中查,查不到的时候如果配置了二级缓存,会从二级缓存中查找,如果还查不到,再查询数据库,把结果按照ID放入到缓存中

④:进行delete、update、add操作时会同时更新缓存

(三)、查询缓存:

     查询缓存是对普通属性结果集的缓存,对实体对象的结果集只缓存id,对于经常使用的查询语句,如果启用了查询缓存,当第一次执行查询语句时,Hibernate会把查询结果存放在二级缓存中,以后再次执行该查询语句时,只需从缓存中获得查询结果,从而提高查询性能,查询缓存中以键值对的方式存储的,key键为查询的条件语句(具体的key规则应该是:类名+方法名+参数列表),value为查询之后等到的结果集的ID列表。查询缓存的一般过程如下:

①:Query Cache保存了之前查询执行过的Select SQL,以及结果集等信息组成一个Query Key

②:当再次遇到查询请求的时候,就会根据Query Key从Query Cache中找,找到就返回,但如果两次查询之间,数据表发生数据变动的话,hbiernate就会自动清除QueryCache中对应的Query Key

我们从查询缓存的策略中可以看出,Query Cache只有在特定的条件下才会发挥作用,而且要求相当严格:

①:完全相同的Select SQL重复执行

②:重复执行期间,Query Key对应的数据表不能有数据变动

好了,基本的概念就说到这,可能对于当当接触的小白们会觉得云里雾里,下面,用代码来说明..........

在看具体的测试代码之前,我们把一些准备工作做好,配置查询缓存和二级缓存

hibernate.cfg.xml

<?xml version='1.0' encoding='utf-8'?>
<!DOCTYPE hibernate-configuration PUBLIC
"-//Hibernate/Hibernate Configuration DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-configuration-3.0.dtd"> <!-- 注意顺序:property->mapping->class-cahche -->
<hibernate-configuration>
<session-factory>
<!-- 开启缓存 --> <!-- 开启二级缓存 -->
<property name="hibernate.cache.use_second_level_cache">true</property>
<!-- 指定二级缓存产品的提供商 -->
<property name="cache.region.factory_class">org.hibernate.cache.EhCacheRegionFactory</property>
<!-- 开启查询缓存 -->
<property name="hibernate.cache.use_query_cache">true</property> <!-- 映射的文件 -->
<mapping class="com.myoracle.entity.User" />
<mapping class="com.myoracle.entity.Teacher" /> <!-- 指定User类使用二级缓存 -->
<class-cache usage="read-only" class="com.myoracle.entity.User"></class-cache>
</session-factory>
</hibernate-configuration>
applicationContext.xml
<?xml version="1.0" encoding="UTF-8"?>

<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context"
xmlns:aop="http://www.springframework.org/schema/aop" xmlns:tx="http://www.springframework.org/schema/tx"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-2.5.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-2.5.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop-2.5.xsd
http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx-2.5.xsd"> <bean id="myDataSource"
class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<property name="driverClassName" value="oracle.jdbc.driver.OracleDriver"></property>
<property name="url" value="jdbc:oracle:thin:@localhost:1521:wyoracle" />
<property name="username" value="scott" />
<property name="password" value="123456" />
</bean> <bean id="sessionFactory"
class="org.springframework.orm.hibernate4.LocalSessionFactoryBean">
<property name="dataSource" ref="myDataSource"></property>
<property name="hibernateProperties">
<props>
<prop key="hibernate.dialect">org.hibernate.dialect.Oracle9Dialect</prop>
<prop key="hibernate.show_sql">true</prop>
<prop key="hibernate.hbm2ddl.auto">update</prop>
<prop key="hibernate.format_sql">true</prop>
</props>
</property>
<property name="configLocations">
<list>
<value>classpath:hibernate.cfg.xml</value>
</list>
</property>
</bean>
<bean id="transactionManager"
class="org.springframework.orm.hibernate4.HibernateTransactionManager">
<property name="sessionFactory" ref="sessionFactory"></property>
</bean> <tx:annotation-driven transaction-manager="transactionManager" />
</beans>

下面我们开始测试各种情况下的代码(补充:如果想关闭二级缓存,只要在hibernate.cfg.xml中将hibernate.cache.use_second_level_cache的value设置false即可;同时,开启查询缓存,除了在hibernate.cfg.xml中有以上配置外,还需要在底层代码中加上query.setCacheable(true);// 手动开启查询缓存)只有这两点下面就看代码吧

①:查询缓存开启、二级缓存关闭*****普通属性查询

    @RequestMapping("/mycache")
public String myCache() { List<String> strings = this.userServiceImpl
.search("select u.username from User u where id<4 order by id asc");
for (String str : strings) {
System.out.println("username:" + str);
} System.out.println("===================================");
List<String> strings2 = this.userServiceImpl
.search("select u.username from User u where id<4 order by id asc");
for (String str : strings2) {
System.out.println("username:" + str);
} return "/mycache";
}

当前二级缓存为关闭状态,我们首先看看查询缓存关闭时的查询结果:

    @SuppressWarnings("unchecked")
public List<String> search(String hql) {
List<String> rtnStrs = new ArrayList<String>();
try { Session session = this.sessionFactory.openSession();
session.beginTransaction();
Query query = session.createQuery(hql);
//query.setCacheable(true);// 手动开启查询缓存
rtnStrs = (List<String>) query.list();
session.getTransaction().commit();
} catch (Exception e) {
System.out.println("DAO层根据HQL语句查询失败");
}
return rtnStrs;
}

上面代码中屏蔽了query.setCacheable(true)。

关闭二级缓存、关闭查询缓存  运行如下:

开启查询缓存、关闭二级缓存 运行如下

结论:对于查询普通属性,无论二级缓存是否开启,只要开启了查询缓存,当两次执行的sql语句相同时,第二次不会发出sql语句,直接从内存中获取。

②:查询缓存开启、二级缓存关闭*******查询实体对象

    /**
* 查询缓存开启,二级缓存关闭*******查询实体对象
*
* 运行结果:如果关闭查询缓存和二级缓存,在两次查询时都发出sql语句,此时为两条查询语句
*
* 运行结果:如果开启查询缓存,关闭二级缓存,第二次会发出根据ID查询实体的n条查询语句
*
* 运行结论:第一次执行list时,会把查询对象的ID缓存到查询缓存中,第二次执行list时(两次的查询SQL语句必须相同),会遍历查询缓存中的ID到
* (一级、二级)缓存里找实体对象, 此时没有,则发出查询语句到数据库中查询
*
* @return
*/
@RequestMapping("/mycache3")
public String mycache3() { List<User> users1 = this.userServiceImpl.search();
for (User u : users1) {
System.out.println("users1:username:" + u.getUsername());
} System.out.println("===============");
List<User> users2 = this.userServiceImpl.search();
for (User u : users2) {
System.out.println("users2:usersname:" + u.getUsername());
} return "/mycache";
}

开启查询缓存、关闭二级缓存 运行如下:(两次都发出sql,而且第二次发出n条语句)

开启查询缓存、关闭二级缓存 运行如下(只发出一条语句)

分析:

一、当只是用hibernate查询缓存,而关闭二级缓存的时候:

①如果查询的是部分属性结果集,那么当第二次查询的时候就不会发出SQL语句,直接从Hibernate查询缓存中取数据

②如果查询的是实体结果集(eg.from User)这个HQL,那么查询出来的实体,首先hibernate查询缓存存放实体的ID,第二次查询的时候,就到hibernate查询缓存中取出ID一条一条的到数据库查询,这样将发出N条SQL语句,造成SQL泛滥。

二、当开启Hibernate查询缓存和二级缓存的时候:

①如果查询的是部分属性结果集,这个和上面只用hbiernate查询缓存而关闭二级缓存的时候一致,因为不涉及实体,不会用到二级缓存。

②如果查询的是实体结果集(eg.from User),那么查询出来的实体首先在查询缓存中存放实体的ID,并将实体对象保存到二级缓存中,第二次查询的时候,就到hibernate查询缓存中取ID,根据ID去二级缓存中匹配数据,如果有数据就不会发出sql语句,如果都有,第二次查询一条SQL语句都不会发出,直接从二级缓存中取数据。

个人总结:在使用查询缓存的时候,最好配合开启二级缓存........

Hibernate缓存之初探的更多相关文章

  1. Hibernate 缓存机制浅析

    1. 为什么要用 Hibernate 缓存? Hibernate是一个持久层框架,经常访问物理数据库. 为了降低应用程序对物理数据源访问的频次,从而提高应用程序的运行性能. 缓存内的数据是对物理数据源 ...

  2. hibernate缓存机制(转)

    原文出处:http://www.cnblogs.com/wean/archive/2012/05/16/2502724.html 一.why(为什么要用Hibernate缓存?) Hibernate是 ...

  3. 【转】hibernate缓存:一级缓存和二级缓存

    什么是缓存? 缓存是介于物理数据源与应用程序之间,是对数据库中的数据复制一份临时放在内存中的容器,其作用是为了减少应用程序对物理数据源访问的次数,从而提高了应用程序的运行性能.Hibernate在进行 ...

  4. Hibernate缓存(转)

    来自:http://www.cnblogs.com/wean/archive/2012/05/16/2502724.html 一.why(为什么要用Hibernate缓存?) Hibernate是一个 ...

  5. 初识Hibernate 缓存

    生活就像一杯咖啡,让你我慢慢的品尝,品尝它的苦涩和甘甜...... 一.什么是Hibernate缓存. 解析:白话来说就是缓存数据的容器 官方标准点缓存:是计算机领域的概念,它介于应用程序和永久性数据 ...

  6. Hibernate缓存原理与策略

    Hibernate缓存原理: 对于Hibernate这类ORM而言,缓存显的尤为重要,它是持久层性能提升的关键.简单来讲Hibernate就是对JDBC进行封装,以实现内部状态的管理,OR关系的映射等 ...

  7. [原创]java WEB学习笔记93:Hibernate学习之路---Hibernate 缓存介绍,缓存级别,使用二级缓存的情况,二级缓存的架构集合缓存,二级缓存的并发策略,实现步骤,集合缓存,查询缓存,时间戳缓存

    本博客的目的:①总结自己的学习过程,相当于学习笔记 ②将自己的经验分享给大家,相互学习,互相交流,不可商用 内容难免出现问题,欢迎指正,交流,探讨,可以留言,也可以通过以下方式联系. 本人互联网技术爱 ...

  8. Hibernate缓存原理与策略 Hibernate缓存原理:

    Hibernate缓存原理: 对于Hibernate这类ORM而言,缓存显的尤为重要,它是持久层性能提升的关键.简单来讲Hibernate就是对JDBC进行封装,以实现内部状态的管理,OR关系的映射等 ...

  9. Hibernate 缓存机制

    一.why(为什么要用Hibernate缓存?) Hibernate是一个持久层框架,经常访问物理数据库. 为了降低应用程序对物理数据源访问的频次,从而提高应用程序的运行性能. 缓存内的数据是对物理数 ...

随机推荐

  1. 解决jsp下载文件,迅雷下载路径不显示文件名称的问题

    如果浏览器安装了迅雷的插件,在jsp页面调用java后台实现文件下载功能时,会自动弹出迅雷下载,迅雷的下载路径会显示.do或者.xhtml之类的,为了解决这个问题,jsp页面修改如下: 写一个< ...

  2. Windows下单机安装Spark开发环境

    机器:windows 10 64位. 因Spark支持java.python等语言,所以尝试安装了两种语言环境下的spark开发环境. 1.Java下Spark开发环境搭建 1.1.jdk安装 安装o ...

  3. C Primer Plus(第五版)12

    第 12 章 存储类, 链接和内存管理 在本章中你将学习下列内容 . 关键字: auto, extern, static, register, const, volatile, restricted. ...

  4. Flex帮助文档ASDoc

    首先,我们一般会对类文件的类和成员以及成员函数做一些解析性说明.那么这个解析性说明应该怎么写呢?如果想给指定的类.成员属性.成员函数加上注释,可以在这些声明的顶部按照下面的格式属性注释: (在flas ...

  5. 约瑟夫(环)问题(Josephus problem)

    问题描述:皇帝决定找出全国中最幸运的一个人,于是从全国选拔出 n 个很幸运的人,让这 n 个人围着圆桌进餐,可是怎么选择出其中最幸运的一个人呢?皇帝决定:从其中一个人从 1 开始报数,按顺序数到第 k ...

  6. fw: openstack

    OpenStack既是一个社区,也是一个项目和一个开源软件,它提供了一个部署云的操作平台或工具集.其宗旨在于,帮助组织运行为虚拟计算或存储服务的云,为公有云.私有云,也为大云.小云提供可扩展的.灵活的 ...

  7. C++设计模式-AbstractFactory抽象工厂模式

    AbstractFactory 要创建一组相关或者相互依赖的对象 作用:提供一个创建一系列相关或相互依赖对象的接口,而无需指定它们具体的类. UML结构图: 抽象基类: 1)AbstractProdu ...

  8. jquery事件合集

    1.在input输入数据时执行的事件(边输入边触发事件) $("input[id='subjectNum']").bind('input propertychange', func ...

  9. Device Path in WinPrefetchView

    As we know that the Prefetch file is used for optimizing the loading time of the application in the ...

  10. 小杨同学git使用记(适合使用过git但是不熟练的童鞋)

    首先声明:这不是一篇git使用手册或者指南,如果要详细的git使用指南,下面是廖雪峰的git教程,可以系统学习廖雪峰的git教程,当然,如果你想马上以一种正确的方式使用git,那么接下来你很快就会学会 ...