Java实战之02Hibernate-08二级缓存
十四、Hibernate的二级缓存
1、Hibernate的缓存结构
2、由于二级缓存被多线程共享,就必须有一定的事务访问策略
非严格读写:READ UNCOMMITTED
读写型:READ COMMITTED
事务型:REPEATABLED READ
只读型:SERIALIZABLE
适合放入二级缓存中的数据:
很少被修改
不是很重要的数据, 允许出现偶尔的并发问题
不适合放入二级缓存中的数据:
经常被修改
财务数据, 绝对不允许出现并发问题
与其他应用数据共享的数据
3、缓存提供的供应商
3.1、各个提供商介绍
Hibernate 的二级缓存是进程或集群范围内的缓存, 缓存中存放的是对象的散装数据,二级缓存是可配置的的插件, Hibernate 允许选用以下类型的缓存插件:
a) EHCache: 可作为进程范围内的缓存, 存放数据的物理介质可以是内存或硬盘, 对 Hibernate 的查询缓存提供了支持
b) OpenSymphony `:可作为进程范围内的缓存, 存放数据的物理介质可以是内存或硬盘, 提供了丰富的缓存数据过期策略, 对 Hibernate 的查询缓存提供了支持
c) SwarmCache: 可作为集群范围内的缓存, 但不支持 Hibernate 的查询缓存
d) JBossCache:可作为集群范围内的缓存, 支持 Hibernate 的查询缓存
3.2、采用EHCache第三方组件
3.2.1、把所需jar包加入到构建路径中:
- <!-- 开启hibernate的二级缓存 -->
- <property name="hibernate.cache.use_second_level_cache">true</property>
- <!-- 配置二级缓存的提供商 -->
- <property name="hibernate.cache.region.factory_class">org.hibernate.cache.ehcache.SingletonEhCacheRegionFactory</property>
3.2.3、在应用中加入EHCache的配置文件
把ehcache-1.5.0.jar包打开,把ehcache-failsafe.xml拷贝出来,去掉里面的注释。并把文件名改为ehcache.xml
- <ehcache xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../config/ehcache.xsd">
- <diskStore path="java.io.tmpdir"/>
- <defaultCache
- maxElementsInMemory="10000"
- eternal="false"
- timeToIdleSeconds="120"
- timeToLiveSeconds="120"
- overflowToDisk="true"
- maxElementsOnDisk="10000000"
- diskPersistent="false"
- diskExpiryThreadIntervalSeconds="120"
- memoryStoreEvictionPolicy="LRU"
- />
- </ehcache>
4、使用二级缓存
4.1、配置使用二级缓存实体
- <!-- 配置哪些类使用二级缓存 -->
- <class-cache usage="read-write" class="cn.itcast.domain.Customer"/>
- <class-cache usage="read-write" class="cn.itcast.domain.Order"/>
- <!-- 配置哪些集合使用二级缓存 -->
- <collection-cache usage="read-write" collection="cn.itcast.domain.Customer.orders"/>
4.2、验证二级缓存是有效的
注意:为了验证二级缓存的存在及有效,先不要使用把session绑定到当前线程上。同时也不要使用getCurrentSession()方法。
- //验证二级缓存确实可用
- @Test
- public void test1(){
- Session s1 = HibernateUtil.getSession();//每次都是获取一个新的Session,不能绑到当前线程上。
- Transaction tx1 = s1.beginTransaction();
- //使用get方法获取一个客户
- Customer c1 = s1.get(Customer.class,1);//会去数据库中查询,把结果放入一级缓存之中。 如果配置了二级缓存,还会把查询结果放入二级缓存之中。
- System.out.println(c1);
- tx1.commit();
- s1.close();//session一关闭,一级缓存就消失了
- Session s2 = HibernateUtil.getSession();//每次都是获取一个新的Session,不能绑到当前线程上。
- Transaction tx2 = s2.beginTransaction();
- //使用get方法获取一个客户
- Customer c2 = s2.get(Customer.class,1);//不查。二级缓存中有
- System.out.println(c2);
- tx2.commit();
- s2.close();
- }
5、类缓存区(Class Cache Region)
明确存的是什么:是对象中的数据,而不是一个对象。
注意:
get和load都可以存和取二级缓存的数据。
Query.list("from Customer")只能存不能取。原因:动态查询。HQL是不一定的。
- /*
- * 类缓存区
- * 都是针对实体类说的,不涉及类中的关联对象。
- * 举例:
- * 如果配置了客户,只涉及客户的信息,不会涉及客户关联的订单!
- * 哪些方法可以操作类缓存区:
- * get和load:
- * 他们都是可以存和取二级缓存中类缓存区的数据。
- * query.list()
- * 它只能存,不能取二级缓存的类缓存区数据
- *
- * 类缓存区,存的是什么?
- * 一级缓存:存的是对象
- * 二级缓存:存的是散装数据。
- * 例如:Cusomert[
- * {id:1,name:'testA',age:20},
- * {id:2,name:'testB',age:28}
- * ]
- */
- @Test
- public void test2(){
- Session s1 = HibernateUtil.getSession();//每次都是获取一个新的Session,不能绑到当前线程上。
- Transaction tx1 = s1.beginTransaction();
- //使用query的list方法,查询所有客户
- Query query1 = s1.createQuery("from Customer");
- List list1 = query1.list();//会去查询,同时把查询结果放入一级缓存。如果配置了二级缓存,也会放入二级缓存。
- System.out.println(list1);
- //使用get方法获取一个客户
- Customer c1 = s1.load(Customer.class,1);//不查,因为一级缓存之中一级有了
- System.out.println(c1);
- tx1.commit();
- s1.close();//session一关闭,一级缓存就消失了
- Session s2 = HibernateUtil.getSession();
- Transaction tx2 = s2.beginTransaction();
- //使用get方法获取一个客户
- Customer c2 = s2.load(Customer.class,1);//不查,因为二级缓存中有
- System.out.println(c2);
- Query query2 = s2.createQuery("from Customer");
- List list2 = query2.list();//会去查询,不会从二级缓存中取数据
- System.out.println(list2);
- tx2.commit();
- s2.close();
- }
6、集合缓存区(Collection Cache Region)
一对多关系映射:操作多的一方就是集合。在配置集合映射时,需注意:
- /*
- * 集合缓存区
- * 要想使用集合缓存区:
- * 1、必须在主配置文件中配置开启集合缓存区。
- * 2、必须同时配置上集合元素的类缓存区。
- * 要想使用orders集合缓存区,以下两行缺一不可
- * <class-cache usage="read-write" class="cn.itcast.domain.Order"/>
- <collection-cache usage="read-write" collection="cn.itcast.domain.Customer.orders"/>
- 集合缓存区,存入的是什么?
- 是只有OID的一个集合。
- 举例:
- {id:1,id:2,id:3,id:4....}
- 执行方式:
- 在使用集合缓存区时,会先从集合缓存区去匹配OID,把匹配上的OID全部取出,到对应的类缓存区去取数据,再生成对象
- */
- @Test
- public void test3(){
- Session s1 = HibernateUtil.getSession();//每次都是获取一个新的Session,不能绑到当前线程上。
- Transaction tx1 = s1.beginTransaction();
- //使用get方法获取一个客户
- Customer c1 = s1.load(Customer.class,1);
- //输出客户的订单
- System.out.println(c1.getOrders());//由于有延迟加载的存在,此时才会去查询。并且把查询结果存入一级缓存之中。同时也会存入二级缓存。
- tx1.commit();
- s1.close();//session一关闭,一级缓存就消失了
- Session s2 = HibernateUtil.getSession();
- Transaction tx2 = s2.beginTransaction();
- //使用get方法获取一个客户
- Customer c2 = s2.load(Customer.class,1);
- //获取该客户的订单
- System.out.println(c2.getOrders());
- tx2.commit();
- s2.close();
- }
7、更新时间戳
当我们修改一级缓存的数据时,会自动同步二级缓存的数据。用的是时间戳原理。
- /*
- * 更新时间戳
- *
- * 时间戳原理:
- * 当一级缓存和二级缓存在创建时,都会有两个时间点。
- * 其一:创建时间
- * 其二:最后修改时间
- * 当执行update后,由于一级缓存已经发生变化了,这时hibernate会用一级缓存的最后修改时就
- * 和二级缓存的最后修改时间进行比较,用离当前时间近的去修改离当前时间远的。
- */
- @Test
- public void test4(){
- Session s1 = HibernateUtil.getSession();//每次都是获取一个新的Session,不能绑到当前线程上。
- Transaction tx1 = s1.beginTransaction();
- //使用get方法获取一个客户
- Customer c1 = s1.get(Customer.class,1);//会查询,同时存入一级缓存和二级缓存
- c1.setName("泰斯特");
- tx1.commit();//由于快照机制,此行会执行更新,同时更新一级缓存。也会更新二级缓存。
- s1.close();//session一关闭,一级缓存就消失了
- Session s2 = HibernateUtil.getSession();//每次都是获取一个新的Session,不能绑到当前线程上。
- Transaction tx2 = s2.beginTransaction();
- //使用get方法获取一个客户
- Customer c2 = s2.get(Customer.class,1);//不查。二级缓存中有
- System.out.println(c2);//输出的【泰斯特】还是【testA】?
- tx2.commit();
- s2.close();
- }
8、EHCache的配置文件
diskStore :指定数据存储位置,可指定磁盘中的文件夹位置
defaultCache : 默认的管理策略
maxElementsOnDisk: 在磁盘上缓存的element的最大数目,默认值为0,表示不限制。
eternal: 设定缓存的elements是否永远不过期。如果为true,则缓存的数据始终有效,如果为false那么还要根据timeToIdleSeconds,timeToLiveSeconds判断。
overflowToDisk: 如果内存中数据超过内存限制,是否要缓存到磁盘上。
timeToIdleSeconds: 对象空闲时间,指对象在多长时间没有被访问就会失效。只对eternal为false的有效。默认值0,表示一直可以访问。
timeToLiveSeconds: 对象存活时间,指对象从创建到失效所需要的时间。只对eternal为false的有效。默认值0,表示一直可以访问。
diskPersistent: 是否在磁盘上持久化。指重启jvm后,数据是否有效。默认为false。
diskExpiryThreadIntervalSeconds: 对象检测线程运行时间间隔。标识对象状态的线程多长时间运行一次。
diskSpoolBufferSizeMB: DiskStore使用的磁盘大小,默认值30MB。每个cache使用各自的DiskStore。
memoryStoreEvictionPolicy: 如果内存中数据超过内存限制,向磁盘缓存时的策略。默认值LRU,可选FIFO、LFU。
FIFO ,first in first out (先进先出).
LFU , Less Frequently Used (最少使用).意思是一直以来最少被使用的。缓存的元素有一个hit 属性,hit 值最小的将会被清出缓存。
LRU ,Least Recently Used(最近最少使用). (ehcache 默认值).缓存的元素有一个时间戳,当缓存容量满了,而又需要腾出地方来缓存新的元素的时候,那么现有缓存元素中时间戳离当前时间最远的元素将被清出缓存。
9、查询缓存区(Query cache)
问题:
Query查询只能存不能取,因为语句是动态的。
解决办法:
按照语句进行存储。使用Map。Map<String,Object>。 key是SQL语句。value是查询的结果集。
这个Map就是查询缓存区。它默认是关闭的。
注意事项:
放到查询缓冲区中的数据,一定要不怎么变化的数据。(并且是非敏感数据,其实放到任何缓存中的数据都应该是非敏感数据)
使用:
a、开启查询缓存区(在hibernate.cfg.xml中配置)
- <!-- 开启hibernate的查询缓存区:有些地方(书籍或者公司)可能会把查询缓存区叫成hibernate的三级缓存 -->
- <property name="hibernate.cache.use_query_cache">true</property>
b、实验是否可用
- /*
- * 为什么query的list方法对二级缓存是能存不能取?
- * 原因:
- * 因为HQL语句是不定的,hibernate没法确定每次查询的HQL语句都是一样。
- *
- * 解决不能取的思路:
- * Map<String hql,Object result> queryCache;
- * 思路:
- * 创建一个新的区域,区域可能是一个map。
- * map的key是查询的HQL语句。
- * map的value是查询的结果集。
- *
- * hibernate的查询缓存区:
- * 1、即是开启了二级缓存,hibernate也不会开启查询缓存区。查询缓存区必须独立开启,且必须是在二级缓存已经开启的基础之上。
- * <!-- 开启hibernate的查询缓存区:有些地方(书籍或者公司)可能会把查询缓存区叫成hibernate的三级缓存 -->
- <property name="hibernate.cache.use_query_cache">true</property>
- 2、在执行查询的时候,需要设置使用查询缓存区
- query1.setCacheable(true);//明确使用查询缓存区
- *
- */
- @Test
- public void test5(){
- Session s1 = HibernateUtil.getSession();//每次都是获取一个新的Session,不能绑到当前线程上。
- Transaction tx1 = s1.beginTransaction();
- Query query1 = s1.createQuery("from Customer");
- query1.setCacheable(true);//明确使用查询缓存区
- List list1 = query1.list();
- System.out.println(list1);
- tx1.commit();
- s1.close();//session一关闭,一级缓存就消失了
- Session s2 = HibernateUtil.getSession();
- Transaction tx2 = s2.beginTransaction();
- Query query2 = s2.createQuery("from Customer");
- query2.setCacheable(true);
- List list2 = query2.list();
- System.out.println(list2);
- tx2.commit();
- s2.close();
- }
Java实战之02Hibernate-08二级缓存的更多相关文章
- JavaEE Tutorials (15) - 对Java持久化API应用使用二级缓存
15.1二级缓存概述190 15.1.1控制实体是否可以缓存19115.2指定缓存模式设置来提高性能192 15.2.1设置缓存获取和存储模式192 15.2.2通过编程方式控制二级缓存194
- 「小程序JAVA实战」小程序数据缓存API(54)
转自:https://idig8.com/2018/09/22/xiaochengxujavashizhanxiaochengxushujuhuancunapi52/ 刚开始写小程序的时候,用户信息我 ...
- TZ_02MyBatis_一级缓存和二级缓存
1.Mybatis中的缓存 1>什么是缓存 存在于内存中的临时数据. 2> 为什么使用缓存 减少和数据库的交互次数,提高执行效率. 3>什么样的数 ...
- mybatis结合redis实战二级缓存(六)
之前的文章中我们意见分析了一级缓存.二级缓存的相关源码和基本原理,今天我们来分享下了mybatis二级缓存和redis的结合,当然mybatis二级缓存也可以和ehcache.memcache.OSC ...
- mybatis结合redis实战二级缓存
之前的文章中我们意见分析了一级缓存.二级缓存的相关源码和基本原理,今天我们来分享下了mybatis二级缓存和redis的结合,当然mybatis二级缓存也可以和ehcache.memcache.OSC ...
- 【Java EE 学习 48】【Hibernate学习第五天】【抓取策略】【二级缓存】【HQL】
一.抓取策略. 1.hibernate中提供了三种抓取策略. (1)连接抓取(Join Fetch):这种抓取方式是默认的抓取方式.使用这种抓取方式hibernate会在select中内连接的方式获取 ...
- [原创]java WEB学习笔记93:Hibernate学习之路---Hibernate 缓存介绍,缓存级别,使用二级缓存的情况,二级缓存的架构集合缓存,二级缓存的并发策略,实现步骤,集合缓存,查询缓存,时间戳缓存
本博客的目的:①总结自己的学习过程,相当于学习笔记 ②将自己的经验分享给大家,相互学习,互相交流,不可商用 内容难免出现问题,欢迎指正,交流,探讨,可以留言,也可以通过以下方式联系. 本人互联网技术爱 ...
- Java面试题:Hibernate的二级缓存与Hibernate多表查询
我们来看两个有关Java框架之Hibernate的面试题,这是关于Hibernate的常考知识点. 1.请介绍一下Hibernate的二级缓存 解题按照以下思路来回答: (1)首先说清楚什么是缓存: ...
- 【.NET Core项目实战-统一认证平台】第十五章 网关篇-使用二级缓存提升性能
[.NET Core项目实战-统一认证平台]开篇及目录索引 一.背景 首先说声抱歉,可能是因为假期综合症(其实就是因为懒哈)的原因,已经很长时间没更新博客了,现在也调整的差不多了,准备还是以每周1-2 ...
随机推荐
- Java条件语句 switch case
不得不说的几点小秘密: 1. switch 后面小括号中表达式的值必须是整型或字符型 2. case 后面的值可以是常量数值,如 1.2:也可以是一个常量表达式,如 2+2 :但不能是变量或带有变量的 ...
- 使用ApplicationLoader中出现报错:The IPA is invalid. It does not inlude a Payload directory
问题处理方法: 1.将achieve的.app后缀的软件包放在一个payload的文件夹中 2.压缩该文件夹,改变.zip后缀为.ipa 3.使用applicationLoader上传该文件
- 【转】C++对象内存分配问题
原文:http://blog.csdn.net/c504665913/article/details/7797859 如果一个人自称为程序高手,却对内存一无所知,那么我可以告诉你,他一定在吹牛.用C或 ...
- ThinkPHP CURD方法盘点:where方法
今天来给大家讲下查询最常用但也是最复杂的where方法,where方法也属于模型类的连贯操作方法之一,主要用于查询和操作条件的设置.where方法的用法是ThinkPHP查询语言的精髓,也是Think ...
- Codeforces Round #323 (Div. 1) B. Once Again... 暴力
B. Once Again... Time Limit: 1 Sec Memory Limit: 256 MB 题目连接 http://codeforces.com/contest/582/probl ...
- android内核读取file文件
内核读取file文件的方法: char* file_read(const char * file_path) { struct file *file = NULL; //保存打开文件的文件指针变量 s ...
- WIX在VS2012中如何制作中文安装包
WIX安装图文并茂简易说明一文中介绍了WIX安装包的制作过程,不过生成的是英文版的,如果需要制作中文版的安装包呢? 方法很简单,只需要两步. 1.增加中文UI的文件WixUI_zh-cn.wxl到工程 ...
- 打开已存在 Android项目及常见的问题
Eclipse 打开已存在 Android项目及常见的问题 1. 点击菜单“File”-- "Import",会弹出 Import 对话框: 2, 选择“General ...
- Folder and jar
- Using zend-navigation in your Album Module
Using zend-navigation in your Album Module In this tutorial we will use the zend-navigation componen ...