Hibernate缓存在工作面试的时候很可能会遇到的问题。
缓存其实就是一块内存空间,充当数据库的内存中的一个临时的容器。
一:hibernate缓存是怎样的?
Hibernate缓存提供了两种缓存:一级缓存和二级缓存。
1 一级缓存又称事务级缓存,Session的缓存。
在Hibernate中一级缓存存是基于Session的生命周期实现的,每一个Session会在内部维护一个数据缓存,她随着Session的创建而创建,销毁而销毁。
一级缓存是必须的,在同一个一级缓存中,每一个持久化类的对象都是唯一的(都有唯一的OID)。
2 二级缓存又称应用级缓存 SessionFactory的缓存 。
在Hibernate中二级级缓存是由SessionFactory实现,所有用一个SessionFactory创建的Session对象共享此缓存。
由于SessionFactory对象的生命周期和应用程序的整个过程对应,因此Hibernate二级缓存是进程范围或者集群范围的缓存,有可能出现并发问题,因此需要采用适当的并发访问策略,该策略为被缓存的数据提供了事务隔离级别。
第二级缓存是可选的,是一个可配置的插件,默认下SessionFactory不会启用这个插件。
什么样的数据适合存放到第二级缓存中?
1) 很少被修改的数据
2) 不是很重要的数据,允许出现偶尔并发的数据
3) 不会被并发访问的数据
4) 常量数据
不适合存放到第二级缓存的数据?
1) 经常被修改的数据
2) 绝对不允许出现并发访问的数据,
3) 与其他应用共享的数据。
二:为什么我们要使用Hibernate缓存?
Hibernate就是对JDBC进行的封装 带来的就是数据访问效率的降低,和性能的下降 对于Hibernate这类ORM而言,缓存显的尤为重要,它是持久层性能提升的关键。
1 Hibernate是一个持久层框架,经常访问物理数据库。
2 为了降低应用程序对物理数据源访问的频次,从而提高应用程序的运行性能。
3 缓存内的数据是对物理数据源中的数据的复制,应用程序在运行时从缓存读写数据,在特定的时刻或事件会同步缓存和物理数据源的数据。
三:怎样使用hibernate缓存?
二级缓存:
1 开始缓存:
为了开启二级缓存,需要在hibernate.cfg.xml文件中配置如下属性:
1 <!-- 开启二级缓存 --> 2 <property name="cache.use_second_level_cache">true</property>
一旦开启了二级缓存,并设置了对某个持久化实体类启动缓存,SessionFactory就会缓存应用访问过的该实体类的每个对象,除非缓存的数据超出缓存空间。
2 在实际应用中,一般不需要开发者自己实现缓存,直接使用第3方提供的开源缓存实现即可。因此在hibernate.cfg.xml文件中设置开启缓存后,还需要设置使用哪种缓存实现类。配置如下:
1 <!-- 设置二级缓存的实现类 --> 2 <property name="cache.region.factory_class">org.hibernate.cache.ehcache.EhCacheRegionFactory</property>
需要注意的是:
3 实际上在项目中使用EHCache缓存实现,仅仅复制liboptional下对应缓存的JAR包还不够,应用EHCache还需要依赖于commons-logging.jar,backport-util-concurrent.jar两个工具包。
4 将缓存实现所需要的配置文件添加到系统的类加载路径中,对于EHCache缓存,它还需要一个ehcache.xml配置文件:
1 <?xml version="1.0" encoding="UTF-8"?> 2 <ehcache> 3 <diskStore path="D:/path"/> <!-- 启用磁盘缓存的位置--> 4 <defaultCache 5 maxElementsInMemory="10000" 6 eternal="false" 7 timeToIdleSeconds="120" 8 timeToLiveSeconds="120" 9 overflowToDisk="true" 10 /> 11 <!-- maxElementsInMemory 设置缓存中最多可放多少个对象 --> 12 <!-- eternal 设置缓存是否永久有效 --> 13 <!-- timeToIdleSeconds 设置缓存的对象多少秒没有被使用就会清理掉 --> 14 <!-- timeToLiveSeconds 设置缓存的对象在销毁之前可以缓存多少秒 --> 15 <!-- overflowToDisk 设置当内存中缓存的记录达到maxElementsInMemory 时是否被持久化到硬盘中,保存路径由<diskStore../>元素指定 --> 16 </ehcache>
5 在实体的缓存策略放在不同的映射文件中分别管理:
1 <?xml version="1.0" encoding="UTF-8"?> 2 <!DOCTYPE hibernate-mapping PUBLIC 3 "-//Hibernate/Hibernate Mapping DTD 3.0//EN" 4 "http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd"> 5 6 <hibernate-mapping> 7 8 <class name="com.cy.beans.Author" table="t_author" catalog="j2ee"> <!-- catalog数据库 --> 9 <!-- 设置缓存策略 --> 10 <cache usage="read-only"/> <!-- 这里--> 11 12 <id name="id" type="java.lang.Long"><!-- 此行的ID,为对象的属性ID --> 13 <column name="id"></column><!-- 此行的ID,为表字段ID --> 14 <generator class="increment"></generator><!-- 给id指定生成策略 --> 15 </id> 16 17 <property name="authorName" type="java.lang.String"> 18 <column name="authorName"></column> 19 </property> 20 21 <!--lazy :lazy是延时的意思,如果lazy=true,那么就是说数据库中关联子表的信息在hibernate容器启动的时候不会加载,而是在你真正的访问到字表非标识字段的时候,才会去加载。 22 反之,如果lazy=false的话,就是说,子表的信息会同主表信息同时加载 23 Hibernate3.x,lazy默认是true; 24 --> 25 <!-- inverse:hibernate双向关系中的基本概念。inverse的真正作用就是指定由哪一方来维护之间的关联关系。当一方中指定了“inverse=false”(默认),那么那一方就有责任负责之间的关联关系 --> 26 27 <set name="books" table="t_book" cascade="all" inverse="true" lazy="false"><!-- set映射节点 --> 28 <key column="fk_author_id"></key><!-- 外键 --> 29 <one-to-many class="com.cy.beans.Book"/><!--one-to-mang节点 --> 30 </set> 31 </class> 32 33 </hibernate-mapping>
缓存同步策略决定了数据对象在缓存中的存取规则.Hibernate中提供了4种不同的缓存同步策略
- read-only:只读.对于不会发生改变的数据可使用
- nonstrict-read-write:如果程序对并发访问下的数据 同步要求不 严格,且数据更新频率较低,采用本缓存 同步策略可获得较 好性能
- read-write:严格的读写缓存.基于时间戳判定机制,实现了“read committed”事务隔离等级.用于对数据同步要求的情况,但不支持分布式缓存,实际应用中使用最多的缓存同步策略.
- transactional:事务型缓存,必须运行在JTA事务环境中.此缓存中, 缓存的相关操作被添加到事务中,如事务失败,则缓冲池的数据 会一同回滚到事务的开始之前的状态.事务型缓存实现了 “Repeatable read”事务隔离等级,有效保证了数据的合法性, 适应于对关键数据的缓存,Hibernate内置缓存中,只有 JBossCache支持事务型缓存.