Hibernate探索之路(四)——缓冲

来源:互联网 发布:java缓冲流的作用 编辑:程序博客网 时间:2024/04/28 13:03

引言:

              缓存就是数据交换的缓冲区(称作Cache),当某一硬件要读取数据时,会首先从缓存中查找需要的数据,如果找到了则直接执行,找不到的话则从内存中找。由于缓存的运行速度比内存快得多,故缓存的作用就是帮助硬件更快地运行。——这个缓冲的概念是我们传统的计算机缓冲概念,也称之为高速缓存区(Cache)。我们今天学习的内容是hibernate框架有关于缓冲的原理与应用。

概述:

              hibernate缓存介于应用程序和数据库之间,其作用是降低应用程序直接访问数据库,进行读写数据操作的频率,从而提高应用程序的性能。这里提到的应用程序可以看作是一个线程,也就是提高了线程的执行效率。

内容:

              一 原理

               hibernate缓冲的核心原理将数据库中的数据复制到该缓冲中,线程执行过程中,直接读写缓冲中的数据,只在某些特定的时刻按照缓冲中的数据来同步更新数据库。通俗理解,线程再访问数据库之前,先去缓冲中查看是否有想要的数据,如果有就取出缓冲中的数据,否则再去数据库中检索相应的数据,同时复制到缓冲中。

               缓冲的物理介质通常都是内存,而数据库的存储介质通常都是硬盘或者磁盘,所以访问缓冲的性能优于访问数据库。

              

              二 分类

             1 hibernate的缓存狭义上分为第一级缓存和第二级缓存。广义上可以分为session缓存和SessionFactory缓存。为什么这么说,因为SessionFactory缓存分为内置缓存和外置缓存,而我们常说的hibernate第二级缓存就是SessionFactory的外置缓存。

                 (1)第一级缓存(Session缓存):Session缓存是内置的,不能被拆卸,代表一块内存空间,在这个空间存放了相互关联的持久化java对象,Session负责根据持久化对象的状态变化来同步更新数据库。

                 (2)第二级缓存(SessionFactory外置缓冲):代表进程或集群范围内的缓存,该缓存中存放的是对象的散装数据。同时该缓存是可配置的插件,实现起来相对复杂,需要考虑并发访问策略和数据过期策略等规范。谈到并发访问策略,简单总结一下分为如下四种策略,每种策略对应一种事务隔离级别:

                          

                   接着介绍一些常用的第二级缓存插件:

                   

             2 缓存的存在具有特定的生命周期,缓存的生命周期与持久化层的缓存的范围息息相关,于是依据这个关系,可以将缓存分为事务级、进程级、集群级。

                 (1) 事务级:缓存只能被当前事务访问,缓存的生命周期依赖于事务的生命周期,事务结束,缓存也结束生命周期。这里的事务可以是数据库事务或者应用事务。每个事务都有独自的缓存,缓存内的数据通常采用相互关联的对象形式。

                 (2) 进程级:该缓存被进程的所有事务共享,缓存的生命周期同样依赖于进程的生命周期。由于进程范围的缓存可能会存放大量数据,物理介质可以是内存或硬盘,缓存内的数据可以采用相互关联的对象形式,也可以采用对象的散装数据形式(类似于序列化形式),性能更优于序列化形式。但是进程级别的缓存支持多个线程共享数据,可能会导致并发访问缓存的问题,有必要对缓存采取事务隔离机制。

                 (3) 集群级:在集群环境中,缓存被同一个机器或多个机器上的多个进程共享,缓存的数据被复制到集群环境中的每个进程节点,进程之间通过远程通信来保证缓存中数据的一致性,缓存中的数据采用对象的散装数据形式。

              三 配置和使用

             第一级缓冲:  当程序调用Session的save()、update()、saveOrUpdate()、load()或get()方法,以及调用Query查询接口的list()、iterate()或filter()方法时,缓存中不存在相应对象,hibernate会把该对象加入到第一级缓存中,当清理缓存时,同步数据库。

                     测试实例代码:

package com.bjpowernode.hibernate;import java.io.Serializable;import java.util.Iterator;import java.util.List;import org.hibernate.Session;import junit.framework.TestCase;public class CacheTest extends TestCase {/** * 在同一个session中发出两次load查询 */public void testCache1() {Session session = null;try {session = HibernateUtils.getSession();session.beginTransaction();Student student = (Student)session.load(Student.class, 1);System.out.println("student.name=" + student.getName());//不会发出查询语句,load使用缓存student = (Student)session.load(Student.class, 1);System.out.println("student.name=" + student.getName());session.getTransaction().commit();}catch(Exception e) {e.printStackTrace();session.getTransaction().rollback();}finally {HibernateUtils.closeSession(session);}}}

             2  第二级缓冲:  

                  1)将ehcache.xml文件拷贝到src下

     2)hibernate.cfg.xml文件的配置      

<hibernate-configuration><session-factory><property name="hibernate.connection.driver_class">com.mysql.jdbc.Driver</property><property name="hibernate.connection.url">jdbc:mysql://localhost:3306/hibernate_cache</property><property name="hibernate.connection.username">root</property><property name="hibernate.connection.password">bjpowernode</property><property name="hibernate.dialect">org.hibernate.dialect.MySQLDialect</property><property name="hibernate.show_sql">true</property><!-- 配置缓存提供商 --><property name="hibernate.cache.provider_class">org.hibernate.cache.EhCacheProvider</property><!-- 启用二级缓存,这也是它的默认配置 --><property name="hibernate.cache.use_second_level_cache">true</property><mapping resource="com/bjpowernode/hibernate/Student.hbm.xml"/><mapping resource="com/bjpowernode/hibernate/Classes.hbm.xml"/><!-- 指定Student使用二级缓存 --><class-cache class="com.bjpowernode.hibernate.Student" usage="read-only"/></session-factory></hibernate-configuration>
     3)测试类中的代码: 
package com.bjpowernode.hibernate;import java.io.Serializable;import java.util.Iterator;import java.util.List;import org.hibernate.CacheMode;import org.hibernate.Session;import junit.framework.TestCase;public class CacheTest extends TestCase {/** * 开启二级缓存 *  * 在两个session中发load查询 */public void testCache1() {//初始化sessionSession session = null;try {//得到一个session对象session = HibernateUtils.getSession();//开启一个事务session.beginTransaction();//加载持久化对象Student student = (Student)session.load(Student.class, 1);System.out.println("student.name=" + student.getName());//提交事务session.getTransaction().commit();}catch(Exception e) {e.printStackTrace();//回滚事务session.getTransaction().rollback();}finally {//关闭session对象HibernateUtils.closeSession(session);}try {session = HibernateUtils.getSession();session.beginTransaction();Student student = (Student)session.load(Student.class, 1);//不会发出查询语句,因为配置二级缓存,session可以共享二级缓存中的数据//二级缓存是进程级的缓存System.out.println("student.name=" + student.getName());session.getTransaction().commit();}catch(Exception e) {e.printStackTrace();session.getTransaction().rollback();}finally {HibernateUtils.closeSession(session);}}}

             3  查询缓存

                1)在前面二级缓存配置文件hibernate.cfg.xml填入如下代码

<!-- 启用查询缓存,默认是false是不起用的 --><property name="hibernate.cache.use_query_cache">true</property>
               2)测试代码: 
/** * 开启查询,关闭二级缓存,采用query.list()查询普通属性 *  * 在一个session中发query.list()查询 */public void testCache1() {Session session = null;try {session = HibernateUtils.getSession();session.beginTransaction();List names = session.createQuery("select s.name from Student s").setCacheable(true).list();for (int i=0; i<names.size(); i++) {String name = (String)names.get(i);System.out.println(name);}System.out.println("-------------------------------------------------------");//不会发出查询语句,因为启用查询缓存names = session.createQuery("select s.name from Student s").setCacheable(true).list();for (int i=0; i<names.size(); i++) {String name = (String)names.get(i);System.out.println(name);}session.getTransaction().commit();}catch(Exception e) {e.printStackTrace();session.getTransaction().rollback();}finally {HibernateUtils.closeSession(session);}}}
          

总结:

              hibernate实际分为第一级缓存和第二级缓存,查询缓存严格说不能是单独划分出来,因为它是在二级缓存的基础上扩展的。

        一级缓存:1  生命周期与session的生命周期一致,都很短,也叫做事务级缓存;2 缓存实体对象,普通对象不予处理;3 在同一个Session中先调用save,再调用load查询刚刚save的数据;4  load、get、iterate查询实体对象或大批量数据更新方法 ; 5 优点:减少数据库访问频率,提高数据访问性能;当缓存中的持久化对象之间存在循环关联关系时,session会保证不出现访问对象死循环以及由于死循环引起的JVM堆栈溢出。

        二级缓存:1 二级缓存生命周期与SessionFactory生命周期一致,SessionFactory可以管理二级缓存;2 使用原则:通常读远远大于写,不经常改变的实体对象;3 用处:用来缓存实体对象,大批量更新数据时,如果配置了二级缓存建议禁用一级缓存和二级缓存的交互。

        查询缓存:1  缓存对象:普通属性结果集,实体对象的结果集id ;2  生命周期:当关联的表发生修改时,查询缓存的生命周期结束。

        各位看客“老爷”,哪里有建议,请在评论中指出,我们共同交流进步。

0 0