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

    xiaoxiao2021-03-26  8

    引言:

                  缓存就是数据交换的缓冲区(称作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() { //初始化session Session 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  生命周期:当关联的表发生修改时,查询缓存的生命周期结束。

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

    转载请注明原文地址: https://ju.6miu.com/read-650144.html

    最新回复(0)