Hibernate缓存(EhCache)

1.什么是缓存:

缓存(Cache )是计算机领域非常通用的概念。它介于应用程序和永久性数据存储源(如硬盘上的文件或者数据库)之间,其作用是降低应用程序直接读写永久性数据存储源的频率,从而提高应用的运行性能。缓存中的数据是数据存储源中数据的拷贝,应用程序在运行时直接读写缓存中的数据,只在某些特定时刻按照缓存中的数据来同步更新数据存储源。
缓存的物理介质通常是内存,而永久性数据存储源的物理介质通常是硬盘或磁盘,应用程序读写内存的速度显然比读写硬盘的速度快,如果缓存中存放的数据量非常大,也会用硬盘作为缓存的物理介质。
缓存的实现不仅需要作为物理介质的硬件,同时还需要用于管理缓存的并发访问和过期等策略的软件。因此,缓存是通过软件和硬件共同实现的

  • 2.为什么使用缓存:
    1)ORM框架访问数据库的效率直接影响应用程序的运行速度,提升和优化ORM框架的执行效率至关重要。
    2)Hibernate的缓存是提升和优化Hibernate执行效率的重要手段,所以学会Hibernate缓存的使用和配置是优化的关键。
    3)评判一个ORM框架是否优秀,访问数据库的频次就一个重要的标准
    而我们今天讲的缓存:并不是指计算机的内存或者CPU的一二级缓存;我们今天讲的是Hibernate所能操作和管理的缓存,并不是内存条中所有的缓存
    备注: 1)Hibernate中的缓存: 用于临时存放数据的内存区域,目的是为了减少应用程序对物理数据源访问的次数,从而提高了程序的运行性能
    2)hibernate查询数据时,首先是到缓存中查找,如果找到就直接使用,如果找不到就再从物理数据源中查找
    3.Hibernate中的缓存管理机制:
    Hibernate中提供了两级Cache,第一级别的缓存是Session级别的缓存,它是属于事务范围的缓存。这一级别的缓存由hibernate管理的,一般情况下无需进行干预;
    第二级别的缓存是SessionFactory级别的缓存,它是属于进程范围或群集范围的缓存。这一级别的缓存可以进行配置和更改,并且可以动态加载和卸载。
    Hibernate还为查询结果提供了一个查询缓存,它依赖于第二级缓存,但是有些人称之为叫查询缓存,或者三级缓存(一般极少用)

一级缓存

  • 1)Hibernate一级缓存又称为"Session缓存",“会话级缓存”
  • 2)通过Session从数据库查询实体时把实体在内存中存储起来,下一次查询同一实体时不再从数据库获取,而是从内存中获取,这就是缓存
  • 3)一级缓存的生命周期和Session相同;Session销毁,他也销毁
  • 4)一级缓存中的数据可适用范围在当前会话之内
  • 2.Hibernate怎样管理一级缓存
    一级缓存是Hibernate的默认缓存,无法取消,用两个方法管理:
    1)evict():用于将某个对象从Session的一级缓存中清除。
    2)clear():用于将一级缓存中的所有对象全部清除
  1. contains(Object obj) 判断指定的对象是否存在于一级缓存中。
    4)flush() 刷新一级缓存区的内容,使之与数据库数据保持同步。
    详细参考项目:Maven_HibernateLx3_Acche中的Test.java
  • 3.什么样的数据放在一级缓存:
    1) 经常被修改的数据   
    2) 绝对不允许出现并发访问的数据,如财务数据,绝对不允许出现并发   
    3) 与其他应用共享的数据

  • 上代码

一级缓存实例

  • 查询两条相同的数据,发现sql只执行了一次
  • 一级缓存是默认开启的
    在这里插入图片描述

清除全部一级缓存

  • session.clear();
  • 清除之后session执行了2次
    在这里插入图片描述

清除某一个对象的一级缓存

  • session.evict(student)
    在这里插入图片描述

判断某个对象是否在一级缓存中

  •             boolean contains = session.contains(student);
    

在这里插入图片描述

刷新缓存

  • session.flush();
    在这里插入图片描述

二级缓存

  • 1.二级缓存:
        Hibernate提供了基于应用程序级别的缓存即为二级缓存,可以跨多个session,即不同的session都可以访问缓存数据。 这个缓存也叫二级缓存。
        Hibernate提供的二级缓存有默认的实现,且是一种可插配的缓存配置!如果用户想用二级缓存,只需要在hibernate.cfg.xml中配置即可; 不想用,直接移除,不影响代码
    PS:Hbernate的二级缓存就是sessionFactory可以依靠Ehcache插件实现
  • 2.什么样的数据放在二级缓存:
    1) 很少被修改的数据   
    2) 不是很重要的数据,允许出现偶尔并发的数据   
    3) 不会被并发访问的数据   
    4) 常量数据

EhCache

  • 1.EhCache 是一个纯Java的进程内缓存框架,具有快速、精干等特点,是Hibernate中默认的CacheProvider
  • 2.主要的特性有:
    1)快速:EhCache直接作用于堆内存和非堆内存所以速度是超级快的,比redis还要快
    2)简单:因为EhCache所依赖的包只有一个SLF4j.jar你不用过多的去关注,而且只是需要简单的配置或者写少许的代码即可
    3)多种缓存策略:
    LRU(Least Recently Used):最近最少使用。当我们把一个元素储存到Cache中或者从Cache中取出时都会更新该元素的最后使用时间。当采用最近最少使用原则进行驱除时会优先把最后使用时间最早的 元素进行驱除。
    LFU(Least Frequently Used):最不常使用的。每次我们从Cache中获取一个元素时都会更新该元素的hitCount属性值加1。当采用最不常使用原则进行驱除时hitCount属性值最小的元素将优先驱除。
    FIFO(First In First Out):先进先出。当采用这种驱除原则时将优先驱除最先储存的元素
  • 4)缓存数据有两级:内存和磁盘,因此无需担心容量问题
  • 5)缓存数据会在虚拟机重启的过程中写入磁盘
  • 6)可以通过RMI、可插入API等方式进行分布式缓存:意思就是它也支持分布式的实现
  • 7)具有缓存和缓存管理器的侦听接口
  • 8)支持多缓存管理器实例,以及一个实例的多个缓存区域
  • 9)提供Hibernate的缓存实现

使用:在pom中引入依赖

  <dependency>
                 <groupId>org.ehcache</groupId>
                 <artifactId>ehcache</artifactId>
                 <version>3.5.2</version>
             </dependency>

java代码的方式实现缓存

package bj.ft.an.EhCache;

import org.ehcache.UserManagedCache;
import org.ehcache.config.builders.UserManagedCacheBuilder;

/**
 * @author LXY
 * @desc
 * @time 2022-10-15  14:48
 */
public class TestEacache {

    public static void main(String[] args) {
        //实例化UserManagedCacheBuilder
        //我们的key是int类型的
        //我们的value是String类型的
        UserManagedCache<Integer, String> map = UserManagedCacheBuilder.newUserManagedCacheBuilder(Integer.class, String.class).build();
        //初始化
        map.init();

        for (int i = 0; i < 20; i++) {
            map.put(i,"这是第"+i+"条");
        }
        
        String s = map.get(10);
        System.out.println(s);

        map.close();
    }
}

在这里插入图片描述

  • 查看UserManagedCacheBuilder的源码,存储的方式是kv类型的数据格式
    在这里插入图片描述

通过xml的方式使用缓存

  • java代码
package bj.ft.an.EhCache;

import org.ehcache.Cache;
import org.ehcache.CacheManager;
import org.ehcache.config.Configuration;
import org.ehcache.config.builders.CacheManagerBuilder;
import org.ehcache.xml.XmlConfiguration;

/**
 * @author LXY
 * @desc
 * @time 2022-10-15  15:02
 */
public class TestEacache2 {
    public static void main(String[] args) {
        //把配置文件转为url对象
        java.net.URL myUrl = TestEacache2.class.getClass().getResource("/ehcache.xml");
        //加载配置文件
        Configuration xmlConfig = new XmlConfiguration(myUrl);
        //获取缓存管理器
        CacheManager cacheManager = CacheManagerBuilder.newCacheManager(xmlConfig);
        cacheManager.init();//初始化

        Cache<String, String> myCache = cacheManager.getCache("myCache", String.class, String.class);

        myCache.put("name","张三");

        System.out.println(myCache.get("name"));

        cacheManager.close();
    }
}

  • ehcache.xml
<?xml version='1.0' encoding='UTF-8'?>
<config xmlns:xsi='http://www.w3.org/2001/XMLSchema-instance'
        xmlns='http://www.ehcache.org/v3'
        xsi:schemaLocation="http://www.ehcache.org/v3 http://www.ehcache.org/schema/ehcache-core.xsd">

    <cache-template name="myTemplate">
        <key-type>java.lang.Long</key-type>
        <value-type>java.lang.String</value-type>
        <heap unit="entries">200</heap>
    </cache-template>

    <!-- 使用模板的情况下,模板的属性是可以进行覆盖的 -->
    <cache alias="myCache" uses-template="myTemplate">
        <key-type>java.lang.String</key-type>
    </cache>


    <!-- 过期策略配置 -->
    <cache alias="myCache1">
        <key-type>java.lang.String</key-type>
        <value-type>java.lang.String</value-type>
        <!-- 缓存过期策略配置,只能配置tti(time to idle)、ttl(time to live)、none、class之中的一种 -->
        <expiry>
            <!-- 空闲指定时间回收 -->
            <tti unit="seconds">5</tti>
            <!-- 存在指定时间回收 -->
        </expiry>
        <resources>
            <!-- 堆内存使用配置 -->
            <!-- 堆内存配置的空间不能大于堆外内存的配置空间 -->
            <heap unit="entries">100</heap>
            <!-- 1、堆外内存使用限制配置 -->
            <!-- 2、使用的空间达到此处配置后,进行回收 -->
            <!-- 3、最小配置为1M,超出指定空间后,无法正常保存(获取的结果为null) -->
            <offheap unit="MB">1</offheap>
        </resources>
    </cache>





</config>

在这里插入图片描述

测试EhCache的缓存过期策略

package bj.ft.an.EhCache;

import org.ehcache.Cache;
import org.ehcache.CacheManager;
import org.ehcache.config.Configuration;
import org.ehcache.config.builders.CacheManagerBuilder;
import org.ehcache.xml.XmlConfiguration;

import java.security.PrivateKey;

/**
 * @author LXY
 * @desc
 * @time 2022-10-15  15:13
 */
public class TestEach3 {
    public static void main(String[] args) {
        //把配置文件转为url对象
        java.net.URL myUrl = TestEacache2.class.getClass().getResource("/ehcache.xml");
        //加载配置文件
        Configuration xmlConfig = new XmlConfiguration(myUrl);
        //获取缓存管理器
        CacheManager cacheManager = CacheManagerBuilder.newCacheManager(xmlConfig);
        cacheManager.init();//初始化

        Cache<String, String> myCache = cacheManager.getCache("myCache1", String.class, String.class);

        String str = "空间大小";
        for (;str.getBytes().length<1024*1024;) {
            str += str;
///将str这个变量给累加成一个大小为1MB的变量,目的是为了要测试一个在ehcahe.xml中配置的内存空间
        }

        myCache.put("name",str);

        System.out.println(myCache.get("name"));

        cacheManager.close();
    }
}

在这里插入图片描述
在这里插入图片描述

Hibernate使用 EhCache开启二级缓存

  • 重构Pom文件
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>bj.sh.fy</groupId>
    <artifactId>Hibernatemaven</artifactId>
    <version>1.0-SNAPSHOT</version>
    <properties>
        <hibernate.version>5.2.12.Final</hibernate.version>
        <mysql.driver.version>8.0.19</mysql.driver.version>
        <ehcache.version>2.10.0</ehcache.version>
    </properties>
         <dependencies>


             <dependency>
                 <groupId>log4j</groupId>
                 <artifactId>log4j</artifactId>
                 <version>1.2.17</version>
             </dependency>

             <dependency>
                 <groupId>mysql</groupId>
                 <artifactId>mysql-connector-java</artifactId>
                 <version>5.1.36</version>
             </dependency>
             <dependency>
                 <groupId>org.hibernate</groupId>
                 <artifactId>hibernate-core</artifactId>
                 <version>${hibernate.version}</version>
             </dependency>


             <dependency>
                 <groupId>net.sf.ehcache</groupId>
                 <artifactId>ehcache</artifactId>
                 <version>${ehcache.version}</version>
             </dependency>

             <dependency>
                 <groupId>org.hibernate</groupId>
                 <artifactId>hibernate-ehcache</artifactId>
                 <version>${hibernate.version}</version>
             </dependency>

         </dependencies>
</project>

在 ehcache.xml文件中

<?xml version="1.0" encoding="UTF-8"?>
<ehcache xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:noNamespaceSchemaLocation="http://ehcache.org/ehcache.xsd"
         updateCheck="false">
    <!--磁盘存储:将缓存中暂时不使用的对象,转移到硬盘,类似于Windows系统的虚拟内存 -->
    <!--path:指定在硬盘上存储对象的路径 -->
    <!--java.io.tmpdir 是默认的临时文件路径。 可以通过如下方式打印出具体的文件路径 System.out.println(System.getProperty("java.io.tmpdir")); -->
    <diskStore path="E://hibernate" />


    <!--defaultCache:默认的管理策略 -->
    <!--eternal:设定缓存的elements是否永远不过期。如果为true,则缓存的数据始终有效,如果为false那么还要根据timeToIdleSeconds,timeToLiveSeconds判断 -->
    <!--maxElementsInMemory:在内存中缓存的element的最大数目 -->
    <!--overflowToDisk:如果内存中数据超过内存限制,是否要缓存到磁盘上 -->
    <!--diskPersistent:是否在磁盘上持久化。指重启jvm后,数据是否有效。默认为false -->
    <!--timeToIdleSeconds:对象空闲时间(单位:秒),指对象在多长时间没有被访问就会失效。只对eternal为false的有效。默认值0,表示一直可以访问 -->
    <!--timeToLiveSeconds:对象存活时间(单位:秒),指对象从创建到失效所需要的时间。只对eternal为false的有效。默认值0,表示一直可以访问 -->
    <!--memoryStoreEvictionPolicy:缓存的3 种清空策略 -->
    <!--FIFO:first in first out (先进先出) -->
    <!--LFU:Less Frequently Used (最少使用).意思是一直以来最少被使用的。缓存的元素有一个hit 属性,hit 值最小的将会被清出缓存 -->
    <!--LRU:Least Recently Used(最近最少使用). (ehcache 默认值).缓存的元素有一个时间戳,当缓存容量满了,而又需要腾出地方来缓存新的元素的时候,那么现有缓存元素中时间戳离当前时间最远的元素将被清出缓存 -->
    <defaultCache eternal="false" maxElementsInMemory="1000"
                  overflowToDisk="false" diskPersistent="false" timeToIdleSeconds="0"
                  timeToLiveSeconds="600" memoryStoreEvictionPolicy="LRU" />

    <!--name: Cache的名称,必须是唯一的(ehcache会把这个cache放到HashMap里) -->
    <cache name="bj.ft.an.enity.StudentEntity" eternal="false"
           maxElementsInMemory="1" overflowToDisk="true" diskPersistent="true"
           timeToIdleSeconds="0" timeToLiveSeconds="300"
           memoryStoreEvictionPolicy="LRU" />
</ehcache>
  • 配置开启缓存
<?xml version='1.0' encoding='utf-8'?>
<!DOCTYPE hibernate-configuration PUBLIC
        "-//Hibernate/Hibernate Configuration DTD//EN"
        "http://www.hibernate.org/dtd/hibernate-configuration-3.0.dtd">
<hibernate-configuration>
  <session-factory>

    <!-- hibernate 的方言,就是hibernate连接的哪个数据库-->
    <property name="dialect">  org.hibernate.dialect.MySQLDialect </property>
    <!-- 连库4要素-->
    <property name="hibernate.connection.driver_class">com.mysql.jdbc.Driver</property>
    <property name="hibernate.connection.url">jdbc:mysql://localhost:3306/hibernates</property>
    <property name="hibernate.connection.username">root</property>
    <property name="hibernate.connection.password">root</property>

    <!--hibernate的属性配置   这行的意思就是控制台打印sql语句-->
    <property name="show_sql">true</property>
<property name="cache.use_query_cache">true</property>


      <!-- hibernate5<property name="cache.use_query_cache">true</property>
的二级缓存配置 -->
      <!-- 开启二级缓存 -->
      <property name="hibernate.cache.use_second_level_cache">true</property>
      <!-- 开启查询缓存 -->
      <property name="hibernate.cache.use_query_cache">true</property>
      <!-- EhCache驱动 -->
      <!-- 注意:此处必须用hibernate的5.2.12.Final 版本 -->
      <property name="hibernate.cache.region.factory_class">org.hibernate.cache.ehcache.EhCacheRegionFactory</property>


      <!--hibernate的实体映射文件-->
    <mapping resource="ClassesEntity.hbm.xml"/>
    <mapping resource="StudentEntity.hbm.xml"/>
    <mapping resource="UserEntity.hbm.xml"/>
  </session-factory>
</hibernate-configuration>
  • 测试类
package bj.ft.an.test;

import bj.ft.an.enity.ClassesEntity;
import bj.ft.an.enity.StudentEntity;
import org.hibernate.*;
import org.hibernate.cfg.Configuration;
import org.hibernate.sql.Select;

import java.util.*;

/**
 * @author LXY
 * @desc
 * @time 2022-10-15  11:35
 */
public class test {
        public static void main(String [] args){

            //1.加载配置
            //默认去加载Src下的名字为hibernate.cfg.xml的文件为了启动hibernate 框架
            Configuration config=  new Configuration().configure();

            //2.创建sesionFactory对象
            SessionFactory sesionFactory =config.buildSessionFactory();

            //3.获取session
            Session session = sesionFactory.openSession();
            //4.开启事务
            Transaction transation = session.beginTransaction();
            //5.执行持久化操作

            Query from_studen = session.createQuery("from StudentEntity");
            from_studen.setCacheable(true);
            List list1 = from_studen.list();
            System.out.println(list1.size());
            List list2 = from_studen.list();
            System.out.println(list2.size());
            List list3 = from_studen.list();
            System.out.println(list3.size());


            session.flush();

            //6.提交事务


            transation.commit();

            //7:关闭相关对象
            session.close();
            sesionFactory.close();
    }
}

  • 开启二级缓存(生效)
    from_studen.setCacheable(true);
    把这行注释就不生效了
    在这里插入图片描述
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值