缓存(Cache):计算机领域非常通用的概念。它介于应用程序和永久性数据存储源(如硬盘上的文件或者数据库)之间,其作用是降低应用程序直接读写永久性数据存储源的频率,从而提高应用的运行性能。缓存中的数据是数据存储源中数据的拷贝。缓存的物理介质通常是内存。

Hibernate中提供了两个级别的缓存:

  • 第一级别的缓存是 Session 级别的缓存,它是属于事务范围的缓存。这一级别的缓存由 hibernate 管理的。
  • 第二级别的缓存是 SessionFactory 级别的缓存,它是属于进程范围的缓存。

1,一级缓存和二级缓存

Session级别的是一级缓存不需要开发者关心,默认总是有效的,当应用保存持久化实体、修改持久化实体时,Sessioin并不会立即把这种改变flush到数据库,而是缓存在当前Session的一级缓存中,除非程序显式调用Session的flush()方法,或程序关闭Session时才会把这些改变一次性的flush到底层数据库——通过这种缓存,可以减少与数据库交互,从而提高数据库访问性能。

在 Session 接口的实现中包含一系列的 Java 集合,这些 Java 集合构成了 Session 缓存。只要 Session 实例没有结束生命周期,且没有清理缓存,则存放在它缓存中的对象也不会结束生命周期。

Session缓存的操作

  • flush:Session 按照缓存中对象的属性变化来同步更新数据库。

默认情况下 Session 在以下时间点刷新缓存:

  • 显式调用 Session 的 flush() 方法。
  • 当应用程序调用 Transaction 的 commit()方法的时, 该方法先 flush ,然后在向数据库提交事务。
  • 当应用程序执行一些查询(HQL, Criteria)操作时,如果缓存中持久化对象的属性已经发生了变化,会先 flush 缓存,以保证查询结果能够反映持久化对象的最新状态。

flush 缓存的例外情况:如果对象使用 native 生成器生成 OID,那么当调用 Session 的 save() 方法保存对象时, 会立即执行向数据库插入该实体的 insert 语句。

commit () 和 flush() 方法的区别:flush 执行一系列 sql 语句,但不提交事务;commit 方法先调用flush() 方法,然后提交事务,意味着提交事务意味着对数据库操作永久保存下来。

SessionFactory级别的二级缓存时全局性的,应用的所有Session都共享这个二级缓存。不过,SessionFactory级别的二级缓存默认是关闭的,必须由程序显式开启。一旦在应用中开启了二级缓存,当Session需要抓取数据时,Session将会先查找一级缓存,再查找二级缓存,只有当一级缓存和二级缓存中都没有需要抓取的数据时,才会去查找底层数据库。在适当情况下,合理地设置Hibernate的二级缓存也可以很好地提高应用的数据库访问性能。

SessionFactory 的缓存可以分为两类:

  • 内置缓存: Hibernate 自带的, 不可卸载。通常在 Hibernate 的初始化阶段,Hibernate 会把映射元数据和预定义的 SQL 语句放到 SessionFactory 的缓存中,映射元数据是映射文件中数据(.hbm.xml 文件中的数据)的复制。该内置缓存是只读的。
  • 外置缓存(二级缓存):一个可配置的缓存插件。在默认情况下, SessionFactory 不会启用这个缓存插件。外置缓存中的数据是数据库数据的复制,外置缓存的物理介质可以是内存或硬盘。

适合放入二级缓存中的数据:

  • 很少被修改。
  • 不是很重要的数据, 允许出现偶尔的并发问题。

不适合放入二级缓存中的数据:

  • 经常被修改。
  • 财务数据, 绝对不允许出现并发问题。
  • 与其他应用程序共享的数据。

2,开启二级缓存

为了开启Hibernate二级缓存,需要在hibernate.cfg.xml文件中设置如下属性:

<property name="hibernate.cache.use_second_level_cache">true</property>

一旦开启了二级缓存,并且设置了对某个持久化实体类启用缓存,SessionFactory就会缓存应用访问过的该实体类的每个对象,除非缓存的数据超出缓存空间。

实际应用一般不需要开发者自己实现缓存,直接使用第三方提供的开源缓存实现即可。因此,在hibernate.cfg.xml文件中设置开启缓存后,还需要设置使用哪种二级缓存实现类。

<property name="hibernate.cache.region.factory_class">org.hibernate.cache.ehcache.internal.EhcacheRegionFactory</property>

二级缓存是可配置的的插件, Hibernate 允许选用以下类型的缓存:

缓存 缓存实现类 类型 集群安全 查询缓存支持
ConcurrentHashMap org.hibernate.testing.cache.CachingRegionFactory 内存    
EhCache org.hibernate.ache.echache.EhCacheRegionFactory 内存、缓存、事务性、支持集群
Infinispan org.hibernate.cache.infinispan.InfinispanRegionFactory 事务性,支持集群

开启二级缓存

(1)在hibernate.cfg.xml中开启二级缓存。需要做两件事:设置启用二级缓存&设置二级缓存的实现类。

<property name="hibernate.cache.use_second_level_cache">true</property>
<property name="hibernate.cache.region.factory_class">org.hibernate.cache.ehcache.internal.EhcacheRegionFactory</property>

(2)将二级缓存的JAR包添加到项目中:将Hibernate目录下的lib/optional\下的对应缓存的JAR包复制到应用的类加载路径中,另外还需要另外两个JAR包。

(3)将缓存实现所需要的配置文件添加到系统的类加载路径中。对于EhCache缓存,它需要一个ehcache.xml配置文件

<?xml version="1.0" encoding="GBK" ?>
<ehcache><diskStore path="java.io.tmpdir"/><defaultCachemaxElementsInMemory="10000"eternal="false"timeToIdleSeconds="120"timeToLiveSeconds="120"maxElementsOnDisk="10000000"diskExpiryThreadIntervalSeconds="120"memoryStoreEvictionPolicy="LRU"/>
</ehcache>

(4)设置对哪些实体类、实体的那些集合启用二级缓存。这一步有两种方式:

  • 修改要使用缓存的持久化类文件,使用Hibernate提供的@Cache注解修饰该持久化类,或使用该注解修饰集合属性。
  • 在hibernate.cfg.xml文件中使用<class-cache.../>或<collection-cache.../>元素对指定的持久化类、集合属性启用二级缓存。

上面两种设置方式只是存在形式不同,本质完全相同。通常来说,推荐采用第一种方式,在这种方式下,不同实体的缓存策略放在不同的持久化类中管理,更符合软件工程中分而治之的策略。

@Cache(usage = CacheConcurrencyStrategy.READ_ONLY)
public class Animal {private int id;private String name;public Animal() {}//省略get()和set()方法
}

二级缓存的并发访问策略:两个并发的事务同时访问持久层的缓存的相同数据时,也有可能出现各类并发问题。二级缓存可以设定以下 4 种类型的并发访问策略,每一种访问策略对应一种事务隔离级别。

  • 非严格读写(Nonstrict-read-write):不保证缓存与数据库中数据的一致性。提供 Read Uncommited 事务隔离级别,对于极少被修改,而且允许脏读的数据,可以采用这种策略。
  • 读写型(Read-write):提供 Read Commited 数据隔离级别。对于经常读但是很少被修改的数据,可以采用这种隔离类型,因为它可以防止脏读。
  • 事务型(Transactional):仅在受管理环境下适用。它提供了 Repeatable Read 事务隔离级别。对于经常读但是很少被修改的数据,可以采用这种隔离类型,因为它可以防止脏读和不可重复读。
  • 只读型(Read-Only):提供 Serializable 数据隔离级别,对于从来不会被修改的数据,可以采用这种访问策略。

(5)测测试缓存效果

public class Main {public static void main(String[] args) {Configuration conf = new Configuration().configure();ServiceRegistry serviceRegistry = new StandardServiceRegistryBuilder().configure().build();SessionFactory sf = conf.buildSessionFactory(serviceRegistry);Session session =   sf.openSession();session.beginTransaction();List<Animal> list  = (List<Animal>)session.createQuery("from Animal").list();session.getTransaction().commit();System.out.println("----------------------");// 打开第二个SessionSession sess2 = sf.openSession();sess2.beginTransaction();// 根据主键加载实体,系统将直接从二级缓存读取// 因此不会发出查询的SQL语句Animal news = (Animal)sess2.load(Animal.class , 1);System.out.println(news.getName());sess2.getTransaction().commit();}
}

3,管理缓存和统计缓存

1、Session级别的一级缓存是局部缓存,它只对当前Session有效。

对于Session级别的一级缓存而言,所有经过它操作的实体,不管使用save()、update()或saveOrUpdate()方法保存一个对象,还是使用load()、get()、list()、iterate()或scroll()方法获得一个对象,该对象都将被放入Session级别的一级缓存中——在Session调用flush()方法或close()方法之前,这些对象将一直缓存在一级缓存中。

在某些特殊的情况下,列入正在处理一个大对象(开销非常大),可能需要从一级缓存中去掉这个大对象或集合属性,可以调用Session的evict(Object object)方法,将该对象或集合从一级缓存中剔除。如果想把所有的对象都从Session中彻底清除,则调用Session的clear()方法即可。

为了判断某个对象是否处于Session缓存中,可以借助于Session提供的contains(Object object)方法,该方法返回一个boolean值,用于标识某个实例是否处于当前Session的缓存中。

2、SessionFactory级别的二级缓存是全局缓存,它对所有的Session都有效的。

SessionFactory提供了一个getCache()方法,该方法的返回值是Cache对象,通过该对象即可操作二级缓存中的实体、集合等。

Cache cache = sf.getCache();
//清除指定的News对象
cache.evictEntity(New.class,id);
//清除所有的News对象
cache.evictEntiryRegion(News.class);
//清除指定id的News所关联的参与者集合属性
cache.evictCollection("News.actors,id);
//清除所有News所关联的参与者集合属性
cache.evictCollection("News.actors");

为了更好地统计二级缓存中的内容,可以借助于Hibernate的统计API。为了开启二级缓存的统计功能,也需要在hibernate.cfg.xml文件中进行配置。

<!--开启二级缓存的统计功能-->
<property name="hibernate.generate_statistics">true</property>
<!--设置使用结构化方式来维护缓存项-->
<property name="cache.use_structured_entries">true</property>

可以通过如下方式查看二级缓存的内容:

// ----------统计二级缓存----------
Map cacheEntries = sf.getStatistics()// 二级缓存的名字默认与持久化类的类名相同.getSecondLevelCacheStatistics("org.crazyit.app.domain.News").getEntries();
System.out.println(cacheEntries);

4,查询缓存

对于经常使用的查询语句,如果启用了查询缓存,当第一次执行查询语句时,Hibernate 会把查询结果存放在查询缓存中。 以后再次执行该查询语句时,只需从缓存中获得查询结果, 从而提高查询性能,查询缓存依赖于二级缓存。

查询缓存使用于如下场合:

  • 应用程序运行时经常使用查询语句。
  • 很少对与查询语句检索到的数据进行插入, 删除和更新操作。

启用查询缓存的步骤:

  • 置二级缓存, 因为查询缓存依赖于二级缓存。
  • 在 hibernate 配置文件中启用查询缓存。
<property name="hibernate.cache.use_query_cache">true</property>
  • 对于希望启用查询缓存的查询语句, 调用 Query 的 setCacheable() 方法。
public class NewsManager{static Configuration conf = new Configuration().configure();// 以Configuration实例创建SessionFactory实例static ServiceRegistry serviceRegistry = new StandardServiceRegistryBuilder().applySettings(conf.getProperties()).build();static SessionFactory sf = conf.buildSessionFactory(serviceRegistry);public static void main(String[] args) throws Exception{NewsManager mgr = new NewsManager();mgr.cacheQuery();mgr.stat();}private void noCacheQuery(){Session session = sf.getCurrentSession();session.beginTransaction();List titles  = session.createQuery("select news.title from News news")// 其实无需设置,默认就是关闭缓存的。.setCacheable(false).list();for(Object title : titles){System.out.println(title);}System.out.println("-------------------------");// 第二次查询,因为没有使用查询缓存,因此会重新发出SQL语句进行查询titles  = session.createQuery("select news.title from News news")// 其实无需设置,默认就是关闭缓存的。.setCacheable(false).list();for(Object title : titles){System.out.println(title);}session.getTransaction().commit();}private void cacheQuery(){Session session = sf.getCurrentSession();session.beginTransaction();List titles  = session.createQuery("select news.title from News news")// 开启查询缓存.setCacheable(true).list();for(Object title : titles){System.out.println(title);}session.getTransaction().commit();System.out.println("-------------------------");Session sess2 = sf.getCurrentSession();sess2.beginTransaction();// 第二次查询,使用查询缓存,因此不会重新发出SQL语句进行查询titles  = sess2.createQuery("select news.title from News news")// 开启查询缓存.setCacheable(true).list();for(Object title : titles){System.out.println(title);}sess2.getTransaction().commit();}// 开启查询缓存,但使用iterate()方法查询,因此也不能缓存public static void cacheQueryIterator(){Session session = sf.getCurrentSession();session.beginTransaction();Iterator it  = session.createQuery("select news.title from News news")// 开启查询缓存.setCacheable(true).iterate();while(it.hasNext()){System.out.println(it.next());}session.getTransaction().commit();System.out.println("-------------------------");Session sess2 = sf.getCurrentSession();sess2.beginTransaction();// 第二次查询,虽然使用了查询缓存,但由于使用iterate()获取查询结果,// 因此无法利用查询缓存。it  = sess2.createQuery("select news.title from News news")// 开启查询缓存.setCacheable(true).iterate();while(it.hasNext()){System.out.println(it.next());}sess2.getTransaction().commit();}private void stat(){//----------统计查询缓存----------long hitCount = sf.getStatistics()//查询缓存的名字与HQL语句或SQL语句相同.getQueryStatistics("select news.title from News news").getCacheHitCount();System.out.println("查询缓存命中的次数:" + hitCount);}
}

Hibernate:二级缓存相关推荐

  1. Hibernate二级缓存的使用

    1启用Hibernate二级缓存 Hibernate二级缓存分为两部分,class缓存和查询缓存,其获取对象的方式有所不同,但两者也有联系,查询缓存必须以class缓存为基础才能起作用,否则只会使效率 ...

  2. Hibernate 二级缓存使用

    1启用Hibernate二级缓存 Hibernate二级缓存分为两部分,class缓存和查询缓存,其获取对象的方式有所不同,但两者也有联系,查询缓存必须以class缓存为基础才能起作用,否则只会使效率 ...

  3. Hibernate EHCache - Hibernate二级缓存

    Hibernate EHCache - Hibernate二级缓存 欢迎使用Hibernate二级缓存示例教程.今天我们将研究Hibernate EHCache,它是最受欢迎的Hibernate二级缓 ...

  4. 配置Hibernate二级缓存步骤

    配置Hibernate二级缓存步骤: 加入二级缓存的jar包及配置文件 jar包位置:hibernate-release-4.1.8.Final\lib\optional\ehcache下所有jar包 ...

  5. Hibernate二级缓存问题

    相关概念和定义 1.缓存的意义 把一些不常修改,但是又经常用的数据存放到内存中,这样能减少与数据库的交互,提升程序的性能 2.Hibernate中提供了两级缓存: 第一级别的缓存是Session级别的 ...

  6. HibernateEHCache –Hibernate二级缓存

    Welcome to the Hibernate Second Level Cache Example Tutorial. Today we will look into Hibernate EHCa ...

  7. hibernate二级缓存(三) 自定义实现一个简单的hibernate二级缓存

    hibernate二级缓存(三) 自定义实现一个简单的hibernate二级缓存 前面我们已经提及过hibernate内部为二级缓存的扩展做了很多的实现.我们只需要实现RegionFactoryTem ...

  8. spring boot 2.1.4 hibernate二级缓存 Hazelcast实现(一)

    Hazelcast优势网上都可以查到,默认的分布式缓存,使用Hazelcast替换ehcache优势比较明显,也方便项目从单机到发展分布式,而不用再引入其他组件也达到了性能要求,按照springboo ...

  9. Hibernate二级缓存详解(转)

    Hibernate二级缓存详解(转) 本文转载 http://www.blogjava.net/supercrsky/articles/238580.html 与Session相对的是,Session ...

  10. ssh整合hibernate 使用spring管理hibernate二级缓存,配置hibernate4.0以上二级缓存

    ssh整合hibernate 使用spring管理hibernate二级缓存,配置hibernate4.0以上二级缓存 hibernate  : Hibernate是一个持久层框架,经常访问物理数据库 ...

最新文章

  1. 浅析Mysql Join语法以及性能优化
  2. 2013 全国高校计算机等级考试(广西考区)一级笔试试题,全国高校计算机等级考试(广西考区)一级笔试试题卷.PDF...
  3. Java并发编程之:Vector和ArrayList的区别
  4. boost::detail模块实现二分法查找的测试程序
  5. 吐血整理 | 肝翻 Linux 进程调度所有知识点|中奖揭晓
  6. 30岁前不要在乎的29件事(转载)
  7. virtual和override
  8. ecshop程序设置伪静态简单三步骤
  9. 初识java中数组、数组在内存中、越界异常、空指针异常
  10. tomcat 8.5 远程登录管理页面
  11. [HTML5和Flash视频播放器]Video.js 学习笔记(一 ) HLS库:videojs-contrib-hls
  12. 一款好用的三维贴图纹理制作软件:Substance Designer Mac 内附安装教程
  13. 动态规划之流水作业调度问题
  14. [FirefoxOS_开发]Firefox OS Quick Start
  15. AD仿真功能描述文档
  16. php查询google pr值接口api介绍,php获取网站谷歌pr值方法
  17. 初识Linux Kernel 移植 之 dm9621网卡驱动移植
  18. 显示网格(grid)
  19. PCB生产工艺流程一:PCB分类的三大要点
  20. 原神ps无法登录服务器未响应,原神公测常见问题与解答,包括配置需求、数据互通问题...

热门文章

  1. 【有限域生成】本原多项式生成有限域的原理及MATLAB实现
  2. 【软件工程】需求分析文档——需求规格说明书
  3. 机器学习(Machine Learning)深度学习(Deep Learning)资料
  4. hitool java_Hitool打开出现failed to create the java virtual machine
  5. 分享按键精灵中使用大漠插件做后台脚本
  6. 制药企业常用质量管理软件TrackWise概述
  7. 使用c语言的多学科协同仿真软件,一种多学科协同仿真系统及方法与流程
  8. AutoCAD(英文版)中所有英语词汇的翻译
  9. 嵌入式robocode实训-任务三
  10. 下载Google Earth的地图并用ArcMap对其georeferencing