2019独角兽企业重金招聘Python工程师标准>>>

缓存
缓存的实现不仅需要作为物理介质的硬件,同时需要管理缓存的并发访问策略和过期策略的程序(软件)。所以缓存通常是通过软件和硬件共同实现的。

Hibernate提供了两级缓存,第一级缓存是Session的缓存。由于Session对象的声明周期通常对应一个数据库事务或者一个应用事务,因此它的缓存是事务范围的缓存。

SessionFactory的缓存可分为两类:内置缓存和外置缓存
SessionFactory的内置缓存是Hibernate自带的,不可卸载。通常在Hibernate的初始化阶段,Hibernate会把映射元数据和预定义SQL语句存放到SessionFactory的内置缓存中,映射元数据是映射文件中数据的复制,而预定义SQL语句是Hibernate根据映射元数据推导出来的。SessionFactory的内置缓存是只读缓存,应用程序不能修改缓存中的映射元数据和预定义SQL语句,因此SessionFactory无须进行内置缓存与映射文件的同步。
SessionFactory的外置缓存是一个可配置的缓存插件。默认情况下,该缓存插件是关闭的。外置缓存中的数据是数据库数据的复制,外置缓存的物理介质可以是内存或者硬盘。

第一级缓存是必需的,也是不可卸载的。

第二季缓存是可插拔的,它由SessionFactory负责管理。由于SessionFactory对象的生命周期和应用程序的整个进程对应,因此二级缓存是进程范围或集群范围的缓存。 二级缓存中存放的是对象的散装数据。

一级缓存

当应用程序调用Session的save()、update()、saveOrUpdate()、load()、get()方法,以及调用Query查询接口的list()、iterate()或filter()方法时,如果Session的缓存中还不存在相应的对象,Hibernate就会把该对象加入到第一级缓存中。当清理缓存时,Hibernate会根据缓存中对象的状态变化来同步更新数据库。

二级缓存

在实际中引入缓存(二级缓存)必须考虑的问题
1.数据库是否与其它应用共享
如果是的话,通常意味着可能不得不放弃使用缓存。因为当前应用运行过程中,其它应用可能同时更新数据库。所以这种情况下,缓存策略的指定就需要格外小心。这种情况下,采取一些保守策略(避免缓存机制的使用)可能更加稳妥。
2.应用是否需要部署在集群环境中

这意味着必须考虑是否引入分布式缓存机制,以及引入分布式缓存带来的实际性能变化。
3.对哪些数据应用二级缓存
显然,对数据库中所有的数据都实施缓存是最简单的方法,大多数情况下,这可能是实际开发中最常采用的模式。但某些情况下,这会对性能造成影响。
比如,电信话务系统,客户通过系统可以查询自己的历史通话记录。对于每个客户,库表中可能都有成千上万条数据,而不同客户之间,基本不可能共享数据(客户只查询自身的通话记录),如果对表进行缓存管理,可以想象,内存会迅速被几乎不可能再被重用的数据充斥,系统性能会急剧下降。
因此,在考虑缓存机制应用策略时,我们必须对当前系统 的数据逻辑进行考察,以确定最佳的解决方案。
如果数据满足以下条件,则可将其纳入缓存管理。

  1. 数据不会被第三方应用修改
  2. 数据大小在可接受的范围之内
  3. 数据更新频率低
  4. 同一数据可能会被系统频繁引用
  5. 非关键数据(非金融财务数据等)

配置二级缓存主要包含以下步骤:
1.选择需要使用二级缓存的持久化类,设置它的第二级缓存的并发访问策略。
2.选择合适的缓存插件。
每一种缓存插件都自带有配置文件。EHCache缓存的配置文件为ehcache.xml,而JBossCache缓存的配置文件为treecache.xml。
在缓存的配置文件中通常需要为每个第二级缓存设置数据过期策略。

配置进程范围内的二级缓存

以EHCache缓存为例,配置步骤如下。
1.开启hibernate的二级缓存

<!-- 开启查询缓存  -->
<property name="hibernate.cache.use_query_cache">true</property>

2.指定缓存提供商

<!-- 指定缓存提供商 -->
<property name="hibernate.cache.provider_class">org.hibernate.cache.EhCacheProvider
</property>

3.指定使用二级缓存的类和集合
这里有两种方式。配置在hbm映射文件中或者配置在hibernate.cfg.xml中。如果使用前者,当映射文件较多时,非常的麻烦。而使用后者,则一目了然,管理方便。
方式一:在每个xx.hbm.xml中配置
Hibernate允许在类和集合上设置第二级缓存。在映射文件中,<class>和<set>元素都有<cache>子元素,这个子元素用来配置第二级缓存。

<cacheusage="transaction|read-write|nonstrict-read-write|read-only"region="RegionName"include="all|non-lazy"
/>

usage属性:必须的,指定并发访问策略
region属性:可选的。指定第二级缓存的区域的名字,默认值为类或集合的名字
include属性:可选的。如果取值为non-lazy,表示当缓存一个对象时,不会缓存它的映射为延迟加载(lazy熟悉为true)的属性。默认为all。

方式二: 全部配置到hibernate.cfg.xml中 (推荐)

<!-- 指定使用二级缓存的类 -->
<class-cache usage="read-write" class="mypack.domain.Customer"/>
<class-cache usage="read-write" class="mypack.domain.Order"/><!-- 指定放入二级缓存的集合 -->
<collection-cache usage="read-write" collection="mypack.Customer.orders"/>

4.配置ehcache.xml

<ehcache><diskStore path="C:\\temp"/><defaultCachemaxElementsInMemory="10000"eternal="false"timeToIdleSeconds="120"timeToLiveSeconds="120"overflowToDisk="true"/><cache name="mypack.Customer"maxElementsInMemory="1"eternal="false"timeToIdleSeconds="300"timeToLiveSeconds="600"overflowToDisk="true"/><cache name="mypack.Customer.orders"maxElementsInMemory="1000"eternal="true"overflowToDisk="false"/> <cache name="mypack.Order"maxElementsInMemory="10000"eternal="false"timeToIdleSeconds="300"timeToLiveSeconds="600"overflowToDisk="true"/> <cache name="customerQueries"maxElementsInMemory="1000"eternal="false"timeToIdleSeconds="300"timeToLiveSeconds="600"overflowToDisk="true"/></ehcache>

<diskStore>元素:缓存数据存放的路径
<defaultCache>元素:缓存的默认过期策略
<cache>元素:设定具体的第二级缓存的数据过期策略。

证明二级缓存存在(起作用)

@Test
public void testSecondLevelCache(){Session session=HibernateUtils.getSession();Transaction tx=session.beginTransaction();Customer c1=(Customer) session.get(Customer.class,2);//放入一级缓存和二级缓Customer c2=(Customer) session.get(Customer.class,2);//①没发sql。直接从第一级缓存获取System.out.println(c1==c2);//<1>truetx.commit();session.close();//②session关闭,一级缓存消失session=HibernateUtils.getSession();//新的sessiontx=session.beginTransaction();Customer c3=(Customer) session.get(Customer.class,2);//③没发sql。直接从第二级缓存中获取System.out.println(c1==c3);//<2>false
}

测试结果:③没有发sql,证明二级缓存起作用了。
注意:<1>处: 结果为true。c1和c2都是从一级缓存中获取的。
              <2>处: 结果为false。c1是从一级缓存中获取的,c3是从二级缓存中获取的。
说明:②的作用是排除一级缓存的干扰

配置集群范围内的二级缓存

Ehcache适用于Hibernate应用发布在单个机器中的场合。如果企业应用需要支持成千上万的用户的并发访问,会采用 分布式的集群访问方式,可以用JBossCache作为Hibernate的二级缓存。
相关配置这里不具体赘述。

查询缓存

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

查询缓存适用的场合

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

查询缓存使用的步骤
1.配置二级缓存(因为查询缓存是基于二级缓存的)
   参考上面ehcache的配置。
2.开启查询缓存

<!-- 开启查询缓存 -->
<property name="cache.use_query_cache">true</property>

3.对于希望启用查询缓存的查询语句, 调用 Query 的 setCacheable(true) 方法

query.setCacheable(true);

证明查询缓存起作用了:
这里为了使结果更清晰,通过对比的形式进行测试。
<1>首先,注释掉①④处

@Test
public void testQueryCache(){Session session=HibernateUtils.getSession();Transaction tx=session.beginTransaction();Query query=session.createQuery("from Customer");//query.setCacheable(true);//①设置查询缓存query.list();//②放入一级缓存和二级缓存tx.commit();session.close();//③session关闭,一级缓存消失session=HibernateUtils.getSession();tx=session.beginTransaction();query=session.createQuery("from Customer");//再次创建Query对象(查询条件相同)//query.setCacheable(true);//④设置查询缓存query.list();//⑤发出了sqltx.commit();session.close();
}

测试结果:⑤处发出了sql。因为默认情况list()每次都会发出sql语句。
<2>仅注释掉④处

@Test
public void testQueryCache(){Session session=HibernateUtils.getSession();Transaction tx=session.beginTransaction();Query query=session.createQuery("from Customer");query.setCacheable(true);//<span style="font-family: Arial, Helvetica, sans-serif;">①设置查询缓存</span>query.list();//<span style="font-family: Arial, Helvetica, sans-serif;">②</span>放入一级缓存和二级缓存,放入查询缓存tx.commit();session.close();//session关闭,一级缓存消失session=HibernateUtils.getSession();tx=session.beginTransaction();query=session.createQuery("from Customer");//再次创建Query对象(查询条件相同)//query.setCacheable(true);//④query.list();//⑤tx.commit();session.close();
}

测试结果:⑤处依然发出了sql。
疑问:这时①处设置了查询缓存,为何⑤处依然会发sql?
分析:①处设置了查询缓存,确实执行②时,就会进行查询缓存。但在执行⑤时,由于④处并没有开启,虽然此时存在查询缓存数据,但list()视而不见,依旧查询数据库。
<3>取消①④处的注释

@Test
public void testQueryCache(){Session session=HibernateUtils.getSession();Transaction tx=session.beginTransaction();Query query=session.createQuery("from Customer");query.setCacheable(true);//①设置查询缓存query.list();//放入一级缓存和二级缓存,放入查询缓存tx.commit();session.close();//session关闭,一级缓存消失session=HibernateUtils.getSession();tx=session.beginTransaction();query=session.createQuery("from Customer");//再次创建Query对象(查询条件相同)query.setCacheable(true);//设置查询缓存query.list();//⑤tx.commit();session.close();
}

测试结果: ⑤处没有发出sql,说明使用了查询缓存。
结论:通过<2>和<3>的测试和分析,可以得知
            ①的作用:使用查询缓存,为了执行②时将数据缓存到查询缓存中
            ④的作用:使用查询缓存,为了让5使用②处的查询缓存数据。

遇到的一个DTD问题

hibernate.cfg.xml中配置了二级缓存,还有注册了实体映射关系,但是一直报错。最后根据错误提示,猜测可能是DTD约束的问题,查询DTD的声明才应证了自己的猜测。
  
结论: <mapping>必须放在所有的<property>的后面。相关dtd约束如下:

转载于:https://my.oschina.net/javandroid/blog/878281

hibernate之 一级缓存和二级缓存相关推荐

  1. Hibernate之一级缓存和二级缓存

    1:Hibernate的一级缓存: 1.1:使用一级缓存的目的是为了减少对数据库的访问次数,从而提升hibernate的执行效率:(当执行一次查询操作的时候,执行第二次查询操作,先检查缓存中是否有数据 ...

  2. Hibernate 一级缓存,二级缓存,查询缓存

    概念: 1.什么是缓存呢? 缓存:是计算机领域的概念,它介于应用程序和永久性数据存储源之间. 缓存:一般人的理解是在内存中的一块空间,可以将二级缓存配置到硬盘.用白话来说,就是一个存储数据的容器.我们 ...

  3. Hibernate一级缓存与二级缓存的区别

    一级缓存: 就是Session级别的缓存.一个Session做了一个查询操作,它会把这个操作的结果放在一级缓存中. 如果短时间内这个session(一定要同一个session)又做了同一个操作,那么h ...

  4. Hibernate一级缓存、二级缓存以及查询缓存的关系

    转载自http://blog.csdn.net/maoyeqiu/article/details/50209893 前两天总结了一下二级缓存和查询缓存的关系,但是又有一个新的问题,就是查询缓存缓存到二 ...

  5. Hibernate学习(九)———— 二级缓存和事务级别详讲

    序言 这算是hibernate的最后一篇文章了,下一系列会讲解Struts2的东西,然后说完Struts2,在到Spring,然后在写一个SSH如何整合的案例.之后就会在去讲SSM,在之后我自己的个人 ...

  6. Jpa持久对象状态,一级缓存,二级缓存

    1JPA持久对象的状态 1.1. 临时状态(transient):瞬时状态 刚刚用new语句创建,没有和entityManager发生关系 没有被持久化,不处于entityManager中.该对象成为 ...

  7. 一级缓存和二级缓存的理解

    首先补充下CPU的知识: CPU也就是中央处理器,相当于计算机的大脑: CPU是一块超大规模的集成电路,是一台计算机的运算核心(Core)和控制核心( Control Unit): CPU功能主要是解 ...

  8. mybatis的一级缓存、二级缓存、sqlsession、sqlsessionfactory什么意思?

    mybatis的的一级缓存是SqlSession级别的缓存,一级缓存缓存的是对象,当SqlSession提交.关闭以及其他的更新数据库的操作发生后,一级缓存就会清空. 二级缓存是SqlSessionF ...

  9. hibernate学习之旅之二级缓存

    最近学习的缓存,感觉有了进一步的认识,也感觉到自己只是浅浅的利用缓存,如果真正能够的能够优化hibernate的性能,还需要更加深入(对于项目而言) 好了废话不说了. 讲到Hibernate的二级缓存 ...

最新文章

  1. 阿里疯传,手把手教你如何从0开始开展UI自动化测试?
  2. java stream操作案例
  3. 「树莓派+1万块乐高」打造乐高分类器,树莓派官方转发,网友:我想借来用两天...
  4. ASP.NET Core WebAPI中的分析工具MiniProfiler
  5. java质因数算法_Java分解任意输入数的质因数算法的实现示例
  6. 如何导出maven子项目_如何使用maven 轻松重构项目
  7. 【Linux网络编程】循环服务器之TCP模型
  8. click vue 重复调用_VUE防止多次点击,重复请求
  9. 含根号的导数怎么求_数学分析Mathematical Analysis笔记整理 第四章 导数与微分
  10. 脚踏实地,才能顶天立地!
  11. 【clickhouse】clickhouse TCP 方式发送数据 ClickHouse-Native-JDBC
  12. linux shell脚本读取配置文件 val=1,shell脚本
  13. 基于pytorch-openpose框架的的人体姿态检测
  14. 代码:灰度重心法求激光中心线(matlab)
  15. 强化学习(RL)原理以及数学模型
  16. python 探索性分析_python中的探索性文本分析
  17. JavaScript编程入门
  18. android 调出键盘表情_Android高仿微信表情输入与键盘输入详解
  19. selenium使用 webdriver.Chrome() 报错,找不到执行文件的解决方法(一)
  20. (转载)书蕴——基于书评的人工智能推荐系统

热门文章

  1. linux 消息队列实例
  2. flex 3.0序列号
  3. 【原创视频教程】学生信息管理系统5--学员成绩管理
  4. 终于把论文Check完了
  5. js模块化编程之CommonJS和AMD/CMD
  6. git克隆远程项目并创建本地对应分支
  7. Linux基础知识99问(一)
  8. JAV A获取项目路径
  9. 使用Lucene.Net实现全文检索
  10. configure,pkg-config和PKG_CONFIG_PATH