数据层的访问效率优化可能第一想到的就是利用缓存,缓存的机能可以简单理解为将从数据库中访问的数据放在内存中,在以后再次使用到这些数据时可以直接从内存中读取而不必要再次访问数据库,尽量减少和数据库的交互提高性能,在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. IOS框架研究之SDWebImage的原理以及使用流程

    SDWebImage 这个类库提供一个UIImageView类别以支持加载来自网络的远程图片.具有缓存管理.异步下载.同一个URL下载次数控制和优化等特征. SDWebImage 支持异步的图片下载+ ...

  2. BroadcastReceiver和EventBus区别是什么

    BroadcastReceiver和EventBus区别是什么?他俩都挺像的,什么时候用BroadcastReceiver,什么时候用EventBus呢? Android广播分为两个方面:广播发送者和 ...

  3. chrome设置可以跨域访问

    右键chrome的快捷方式->属性 修改目标属性:添加--args --disable-web-security  --user-data-dir=F:\MyChromeDevUserData, ...

  4. 通过DOM节点操作来获取表单信息

    这是之前突发奇想地用dom节点的关系来操作表单的故事.. 事情的经过是这样的,大概就是一个平台注册后有留言功能,管理员登录之后可以对这些留言进行回复.这个页面呢,就是通过foreach获取到数据库里的 ...

  5. BVT & BAT & SVT

    1. BVT(Build Verification Test) a. BVT概念 Build Verification test is a set of tests run on every new ...

  6. Tomcat从内存、并发、缓存方面优化方法

    Tomcat有很多方面,从内存.并发.缓存四个方面介绍优化方法.   一.Tomcat内存优化 Tomcat内存优化主要是对 tomcat 启动参数优化,我们可以在 tomcat 的启动脚本 cata ...

  7. 用odbc连接oracle问题

    如果用11g的客户端,然后通过odbc(远程连接)连接10g的oracle,会出现监听程序无法启动(ORA-12541: TNS: 无监听程序) 此时需要在客户端目录中D:\instantclient ...

  8. 苹果刷机相关开源代码(如iRecovery等)收集汇总(不断更新中...)

    下面截图是在下面开源代码下使用VS2015修改部分代码后适配而成,可以在Windows平台上运行, 下载连接: http://pan.baidu.com/s/1i4zKGx3.

  9. Hibernate day02笔记

      对象状态与一级缓存 状态介绍 hibernate 规定三种状态:瞬时态.持久态.脱管态 状态     瞬时态:transient,session没有缓存对象,数据库也没有对应记录.         ...

  10. 移动端自动化环境搭建-python的安装

    安装python A.安装依赖 由于 Robot Framework 框架是基于 Python 语言开发的,要想使用 Robot Framework 首先需要有 Python环境. B.安装过程 下载 ...