Hibernate二级/查询缓存的陷阱

这篇文章将介绍如何设置Hibernate二级和查询缓存,它们如何工作以及最常见的陷阱。

休眠二级缓存是用于存储实体数据的应用程序级缓存。 查询缓存是一个单独的缓存,仅存储查询结果。

这两个缓存实际上是并存的,因为在很多情况下,我们都希望在没有其他缓存的情况下使用它们。 如果使用得当,这些缓存可以通过减少命中数据库的SQL语句的数量,以透明的方式提高性能。

第二级缓存如何工作?

第二级缓存存储实体数据,但存储实体本身。 数据以“脱水”格式存储,该格式看起来像哈希图,其中键是实体ID,而值是原始值列表。

这是有关二级缓存内容的外观的示例:

*-----------------------------------------*
|          Person Data Cache              |
|-----------------------------------------|
| 1 -> [ "John" , "Q" , "Public" , null ] |
| 2 -> [ "Joey" , "D" , "Public" ,  1   ] |
| 3 -> [ "Sara" , "N" , "Public" ,  1   ] |
*-----------------------------------------*

当通过Id从数据库entityManager.find()例如,使用entityManager.find()从对象加载对象时,或者遍历惰性初始化关系时,将填充第二级缓存。

查询缓存如何工作?

查询高速缓存在概念上看起来像一个哈希图,其中键由查询文本和参数值组成,并且值是与查询匹配的实体ID的列表:

*----------------------------------------------------------*
|                       Query Cache                        |                     
|----------------------------------------------------------|
| ["from Person where firstName=?", ["Joey"] ] -> [1, 2] ] |
*----------------------------------------------------------*

有些查询不返回实体,而是仅返回原始值。 在那些情况下,值本身将存储在查询缓存中。 执行可缓存的JPQL / HQL查询时,将填充查询缓存。

这两个缓存之间有什么关系?

如果正在执行的查询先前已缓存了结果,则不会有SQL语句发送到数据库。 而是从查询缓存中检索查询结果,然后使用缓存的实体标识符访问第二级缓存。

如果第二级缓存包含给定ID的数据,它将重新水化实体并返回它。 如果第二级缓存不包含该特定ID的结果,则将发出SQL查询以从数据库中加载实体。

如何在应用程序中设置两个缓存

第一步是在类路径中包含hibernate-ehcache jar:

<dependency><groupId>org.hibernate</groupId><artifactId>hibernate-ehcache</artifactId><version>SOME-HIBERNATE-VERSION</version>
</dependency>

需要将以下参数添加到EntityManagerFactorySessionFactory的配置中:

<prop key="hibernate.cache.use_second_level_cache">true</prop>
<prop key="hibernate.cache.use_query_cache">true</prop>
<prop key="hibernate.cache.region.factory_class">org.hibernate.cache.ehcache.EhCacheRegionFactory</prop>
<prop key="net.sf.ehcache.configurationResourceName">/your-cache-config.xml</prop>

首选使用EhCacheRegionFactory而不是SingletonEhCacheRegionFactory 。 使用EhCacheRegionFactory意味着Hibernate将为Hibernate缓存创建单独的缓存区域,而不是尝试重用应用程序中其他位置定义的缓存区域。

下一步是在文件your-cache-config.xml配置缓存区域设置:

<?xml version="1.0" ?>
<ehcache xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"updateCheck="false"xsi:noNamespaceSchemaLocation="ehcache.xsd" name="yourCacheManager"><diskStore path="java.io.tmpdir"/><cache name="yourEntityCache"maxEntriesLocalHeap="10000"eternal="false"overflowToDisk="false"timeToLiveSeconds="86400" /><cache name="org.hibernate.cache.internal.StandardQueryCache"maxElementsInMemory="10000"eternal="falsetimeToLiveSeconds="86400"overflowToDisk="false"memoryStoreEvictionPolicy="LRU" /><defaultCachemaxElementsInMemory="10000"eternal="false"timeToLiveSeconds="86400"overflowToDisk="false"memoryStoreEvictionPolicy="LRU" />
</ehcache>

如果未指定缓存设置,则采用默认设置,但是最好避免这种情况。 通过在ehcache元素中填充name属性,确保为缓存命名。

为缓存指定一个名称可以防止它使用默认名称,该名称可能已经在应用程序的其他位置使用过。

使用二级缓存

现在可以使用二级缓存了。 为了缓存实体,请使用@org.hibernate.annotations.Cache注释对它们进行注释:

@Entity       
@Cache(usage=CacheConcurrencyStrategy.READ_ONLY, region="yourEntityCache")
public class SomeEntity {...
}

关联也可以由二级缓存进行缓存,但是默认情况下不这样做。 为了启用关联的缓存,我们需要将@Cache应用于关联本身:

@Entity       
public class SomeEntity {@OneToMany@Cache(usage=CacheConcurrencyStrategy.READ_ONLY,region="yourCollectionRegion")private Set<OtherEntity> other;     
}

使用查询缓存

配置查询缓存后,默认情况下尚未缓存任何查询。 需要将查询明确标记为已缓存,例如,这是如何将命名查询标记为已缓存:

@NamedQuery(name="account.queryName",query="select acct from Account ...",hints={@QueryHint(name="org.hibernate.cacheable",value="true")}     
})

这是将条件查询标记为已缓存的方法:

List cats = session.createCriteria(Cat.class).setCacheable(true).list();

下一节将介绍一些在尝试设置这两个缓存时可能遇到的陷阱。 这些行为按设计工作,但仍然令人惊讶。

陷阱1 –查询缓存会降低性能,导致大量查询

如果将缓存的查询结果配置为比查询返回的缓存的实体更频繁地过期,则会发生两个缓存的工作方式的有害副作用。

如果查询已缓存结果,它将返回实体ID的列表,然后针对第二级缓存进行解析。 如果具有这些ID的实体未配置为可缓存或它们已过期,则每个实体ID的选择将命中数据库。

例如,如果一个缓存的查询返回了1000个实体ID,而第二级缓存中没有这些实体,则将对数据库发出1000个ID选择。

该问题的解决方案是将查询结果到期配置为与查询返回的实体的到期保持一致。

陷阱2 –与

当前无法为同一父实体的不同子类指定不同的缓存策略。

例如,这将不起作用:

@Entity
@Inheritance
@Cache(CacheConcurrencyStrategy.READ_ONLY)
public class BaseEntity {...
}@Entity
@Cache(CacheConcurrencyStrategy.READ_WRITE)
public class SomeReadWriteEntity extends BaseEntity {...
}@Entity
@Cache(CacheConcurrencyStrategy.TRANSACTIONAL)
public class SomeTransactionalEntity extends BaseEntity {...
}

在这种情况下,仅考虑父类的@Cache注释,并且所有具体实体都具有READ_ONLY并发策略。

陷阱3 –使用基于单例的缓存时,缓存设置将被忽略

建议将缓存区域工厂配置为EhCacheRegionFactory ,并通过net.sf.ehcache.configurationResourceName指定ehcache配置。

此区域工厂的替代方法是SingletonEhCacheRegionFactory 。 对于该区域工厂,使用缓存名称作为查找键将缓存区域存储为单例。

单例区域工厂的问题在于,如果应用程序的另一部分已经在单例中注册了具有默认名称的缓存,则这将导致忽略通过net.sf.ehcache.configurationResourceName传递的ehcache配置文件。

结论

如果设置正确,则二级缓存和查询缓存非常有用,但是要记住一些陷阱,以免发生意外行为。 总而言之,这是一个透明工作的功能,如果使用得当,可以显着提高应用程序的性能。

翻译自: https://www.javacodegeeks.com/2014/06/pitfalls-of-the-hibernate-second-level-query-caches.html

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/363342.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

C#工厂模式-简单工厂

简单工厂: 工厂模式:简单工厂,工厂方法,抽象工厂三种. 简单工厂(力求简洁) 工厂即为生产东西的地方.在C#也有这种模式,充分利用了面向对象语言的三大特征(多态,继承),简单工厂.工厂的功能就是生产,而生产些什么呢?一个工厂可以生产鞋子,生产衣服.它们所处的车间不一样,所以需…

跨域方式

原文地址&#xff1a;https://www.xingkongbj.com/blog/http/cross-origin.html http://www.ruanyifeng.com/blog/2016/04/same-origin-policy.html document.domain iframe 实现父页面与其内部 iframe 页面通讯&#xff0c;要求一级域名相同两个页面设置 document.domain 为相…

Linux学习之四——磁盘与文件系统管理

一、一些基本定义 1. superblock&#xff1a;记录此 filesystem 的整体信息&#xff0c;包括inode/block的总量、使用量、剩余量&#xff0c; 以及文件系统的格式与相关信息等&#xff1b;2. inode&#xff1a;记录档案的属性&#xff0c;一个档案占用一个inode&#xff0c;同时…

使用.Net 1.1的项目,TreeView控件不能正常显示

使用.Net 1.1的项目&#xff0c;TreeView控件不能正常显示&#xff0c;往往是显示一大堆的文字&#xff0c;那是因为脚本没有被执行造成的&#xff0c;需要在web.config里配置一下。<!-- Microsoft WebControls --><MicrosoftWebControls> <add key"Common…

吸气剂/设定者。 邪恶。 期。

从2003年开始&#xff0c;艾伦霍鲁布&#xff08;Allen Holub&#xff09;讨论了为什么吸气剂和塞特方法是邪恶的著名文章&#xff0c;关于吸气剂/塞特方法是否是反模式&#xff0c;应该避免使用&#xff0c;还是我们在面向对象中不可避免地需要它&#xff0c;这是一个古老的争…

你不可不知的数据库northwind

说起northwind&#xff0c;40左右的大年一定不会陌生&#xff0c;它是著名的northwind示例库&#xff0c;在SQL Server 是标配。 它有8张表&#xff0c;涉及客户、商品、订单。 如果你是有志从事企业级应用开发&#xff0c;或有志从事企业互联网开发&#xff0c;一定不要错过no…

angularjs中 $watch 和$on 2种监听的区别?

1.$watch简单使用 $watch是一个scope函数&#xff0c;用于监听模型变化&#xff0c;当你的模型部分发生变化时它会通知你。 $watch(watchExpression, listener, objectEquality); 每个参数的说明如下&#xff1a; watchExpression&#xff1a;监听的对象&#xff0c;它可以是…

【原】.Net创建Excel文件(插入数据、修改格式、生成图表)的方法

1.添加Excel引用 可以在.Net选项卡下添加Microsoft.Office.Interop.Excel引用&#xff0c;或在COM下添加Microsoft Excel 12.0 Object Library。它们都会生成Microsoft.Office.Interop.Excel.dll。 2.创建Excel。 有两种方法创建一个Excel Workbook实例。 1.需要一个模板文件&…

求助:安装程序无法创建一个DCOM用户帐号来注册.....\valec.exe

http://support.microsoft.com/kb/257413/ 这是Visual Studio的一个BUG&#xff0c;只出现在Windows 2000/XP下。如果你不使用Visual Studio Analyzer&#xff0c;可以在安装时选择Custom&#xff0c;然后在Enterprise Tools中清除掉Visual Studio Analyzer。再安…

Spring / Hibernate使用log4jdbc改进了SQL日志记录

Hibernate提供了开箱即用的SQL日志记录&#xff0c;但是这种日志记录仅显示准备好的语句&#xff0c;而不显示发送到数据库的实际SQL查询。 它还不会记录每个查询的执行时间&#xff0c;这对于性能故障排除很有用。 这篇博客文章将介绍如何设置Hibernate查询日志记录&#xff…

快递API接口

快递100 转载于:https://www.cnblogs.com/onesmail/p/10608600.html

js中split()和join()的用法

Split()方法&#xff1a;把一个字符串分割成字符串数组 如上所示&#xff1a;把字符串a按空格分隔&#xff0c;得3个字符串数组。 在如&#xff1a; var a”hao are you” a.split(“”); 得到[h,a,o,a,r,e,y,o,u]; Join方法: 把数组中的所有元素转换为一个字符串 如上图所…

IT行业经典面试题,121套面试题

IT行业经典面试题&#xff0c;121套面试题 资源大小&#xff1a; 580.80KB资源类型&#xff1a;发布人&#xff1a; eyelife 发布日期&#xff1a; 2天前Tag&#xff1a; 名企,计算机 资源分&#xff1a; 10下载人数&#xff1a; 857 4.33/347人评分 12 3 4 5 评论 分享…

词云第一次实践,参考学校老师讲的一些知识点还有网上大佬的代码实现

from wordcloud import WordCloudimport cv2import jiebawith open(1906月考.txt, r, encodingutf-8) as f: # 以读的方式打开词云参考的文档 text f.read() # 阅读cut_text .join(jieba.cut(text)) # 通过jieba库的cut精确模式进行分词# 得到词云形状color_mask cv2…

Spring Integration 4.0:完整的无XML示例

1.简介 Spring Integration 4.0终于发布了 &#xff0c;并且此版本具有非常好的功能。 本文介绍的一种可能性是完全不使用XML即可配置集成流程。 那些不喜欢XML的人仅使用JavaConfig就可以开发集成应用程序。 本文分为以下几节&#xff1a; 介绍。 流程概述。 弹簧配置。 …

http协议组成(请求状态码)

http请求由&#xff1a;请求行&#xff1b;消息报头&#xff1b;请求正文组成 //请求行 Request URL: http://172.32.4.33:8080/operation/v2/autoServer/queryAutoServer.htm //请求地址 Request Method: POST …

CSS伪类的三种写法

今天逛蓝色时&#xff0c;无意发现了有人讨论伪类的正确写法&#xff0c;让我对伪类的认识也更清晰了&#xff0c;转贴于此&#xff0c;以备日后查询(原贴当时没记下地址&#xff0c;已经记不得了) Code<style>a.tb{text-decoration:none;}a.tb:link{color:#FF9900;}a.tb…

sql自动生成golang结构体struct实体类

废话不多说直接上地址 使用地址http://www.linkinstars.com:8090/auto-code 项目github https://github.com/LinkinStars/Auto-Coding 是上次内容的一个更新&#xff0c;方便自己用&#xff0c;希望你也喜欢https://www.cnblogs.com/linkstar/p/10037629.html &#xff08;半个…

如何通过示例在Java中使用CopyOnWriteArraySet

CopyOnWriteArraySet是CopyOnWriteArrayList类的弟弟。 这些是专用集合类&#xff0c;这些类是在JDK 1.5上添加的&#xff0c;以及它们最流行的表亲ConcurrentHashMap 。 它们是并发收集框架的一部分&#xff0c;位于java.util.concurrent包中。 CopyOnWriteArraySet最适合作为…

生成器

一、什么是生成器 通过列表生成式&#xff0c;我们可以直接创建一个列表。但是&#xff0c;受到内存限制&#xff0c;列表容量是有限的。而且&#xff0c;创建一个包含100万个元素的列表&#xff0c;不仅占用很大的存储空间&#xff0c;如果我们仅仅需要访问前面几个元素&#…