Hibernate二级缓存

2020-03-25  本文已影响0人  BlueSkyBlue

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

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

SessionFactory级别的缓存

SessionFactory的缓存分为两类:

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

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

二级缓存的架构

二级缓存的并发访问策略

两个并发的事务同时访问持久层的缓存的相同的数据时,也有可能出现各种各样的并发问题。

二级缓存可以设定为以下四种类型的并发访问策略,每一种访问策略对应一种事务的隔离级别。

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

//启动Hibernate的二级缓存
<property name="cache.use_second_level_cache">true</property>
//配置Hibernate二级缓存使用的产品
<property name="hibernate.cache.region.factory_class">org.hibernate.cache.ehcache.EhCacheRegionFactory</property>
//配置对那些类使用Hibernate的二级缓存
<class-cache usage="read-write" class="com.hibernate.unionsubclass.Student"></class-cache>

也可以在.hbm.xml类中配置二级缓存。

设置集合缓存

我们看下面的代码

SessionFactory sessionFactory = null;
Configuration cfg = new Configuration().configure();
sessionFactory = cfg.buildSessionFactory();
Session session = sessionFactory.openSession();
Transaction transaction = session.beginTransaction();

Category category = session.get(Category.class, 42);
System.out.println(category.getItems().size());

transaction.commit();
session.close();

session = sessionFactory.openSession();
transaction = session.beginTransaction();
Category category2 = session.get(Category.class, 42);
System.out.println(category2.getItems().size());

transaction.commit();
session.close();
sessionFactory.close();

运行后发现生成了四条SQL语句。此时我们给Category类添加入二级缓存。

<class-cache usage="read-write" class="com.hibernate.n2n.Category"></class-cache>

发现少了一条SQL语句,但在获取items的时候还是两条SQL语句,此时我们需要将Item类添加到二级缓存中。

<collection-cache usage="read-write" collection="com.hibernate.n2n.Category.items"></collection-cache>

此时发现又是四条SQL语句。因为我们仅仅缓存了items集合类,没有缓存其中的类型。

<class-cache usage="read-write" class="com.hibernate.n2n.Item"></class-cache>

这个时候控制台只输出了两条SQL语句。

集合缓存也可以在.hbm.xml中配置

<set name="items" table="category_item">
    <cache usage="read-write"/>
    <key>
        <column name="Category_Id"/>
    </key>
    <many-to-many class="Item" column="Item_Id"/>
</set>

注意,还需要在集合包含的类中配置缓存。

ehcache.xml文件

<diskStore path="java.io.tmpdir"/>

diskStore表示磁盘的存储路径。当有大量的数据的时候我们需要设置临界值,如果低于这个临界值,则将数据存入到内存中。高于这个数据则放到磁盘上。该路径表示磁盘的位置。

<defaultCache
    maxElementsInMemory="10000"
    eternal="false"
    timeToIdleSeconds="120"
    timeToLiveSeconds="120"
    overflowToDisk="true"
/>

默认的存储策略。

<cache name="sampleCache1"
   maxElementsInMemory="10000"
   eternal="false"
   timeToIdleSeconds="300"
   timeToLiveSeconds="600"
   overflowToDisk="true"
/>

设置具体的命名缓存数据的策略,每个命名缓存代表一个缓存区域。

缓存区域(region):一个具有名称的缓存块,可以给每个缓存块设置不同的缓存策略。如果没有设置任何缓存区域,则所有的缓存对象将使用默认的缓存策略。

配置项解释:

name:设置缓存的名字,它的取值为类的全限定名或类的集合名字。
maxElementInMemory:在内存中最多可以存储对象的数量。
eternal:设置对象在缓存中是否为永久的,true表示永不过期。此时将忽略timeToIdleSeconds和timeToLiveSecond,默认值为false。
timeToIdleSeconds:设置对象空闲的最长时间,单位是秒。如果超过这个时间,对象将从缓冲中清除。
timeToLiveSecond:设置对象的最长生存时间,超过这个时间,对象过期。如果值为0表示对象可以永久的存在缓存中。
overflowToDisk:设置内存中的缓存中的对象的数量达到上限后,是否把溢出的对象写到基于硬盘的缓存中。

查询缓存

当执行以下的代码

Query query = session.createQuery("from Category ");
List<Category>categories = query.list();
System.out.println(categories.size());

categories = query.list();
System.out.println(categories.size());

我们会发现执行了两条SQL。说明缓存没有起作用。

此时我们需要设置查询缓存。

默认情况下设置的缓存对HQL和QBC查询是无效的。通过以下方式配置
在Hibernate配置文件中声明开启查询缓存

<property name="cache.use_query_cache">true</property>

调用Query或Criteria的setCacheable方法,设置为true。

query.setCacheable(true);

注意:查询缓存依赖二级缓存。

时间戳缓存

时间戳缓存区域存放了对于查询结果相关的表进行插入,更新,删除操作的时间戳。Hibernate通过时间戳缓存区域判断缓存的查询结果是否过期,其运行过程如下:

Query接口的iterator方法

当遍历访问结果集的时候,该方法先到Session缓存及二级缓存中查看是否存在特定OID的对象,如果存在,就直接返回该对象。如果不存在该对象,则通过相应的SQL select语句到数据库中加载特定的实体类对象。

大多数情况下应使用list方法执行查询操作。iterator方法仅在满足以下条件的场景中适合使用,可以稍微提高查询的性能:

上一篇 下一篇

猜你喜欢

热点阅读