Hibernate如何存储二级缓存条目

介绍

使用数据库访问抽象层的好处是可以透明地实现缓存,而不会泄漏到业务逻辑代码中 。 Hibernate Persistence Context充当事务后写式高速缓存 ,将实体状态转换转换为DML语句。

持久性上下文充当逻辑事务存储,并且每个Entity实例最多可以具有一个托管引用。 无论我们尝试加载相同的实体多少次, 休眠会话都将始终返回相同的对象引用。 通常将此行为描述为第一级缓存

Hibernate持久化上下文 本身并不是一个缓存解决方案,服务于不同的目的不是提升应用程序读取操作的性能。 因为休眠会话绑定到当前正在运行的逻辑事务,所以一旦事务结束,该会话将被销毁。

二级缓存

适当的缓存解决方案必须跨越多个Hibernate会话 ,这就是Hibernate还支持其他二级缓存的原因。 第二级缓存绑定到SessionFactory生命周期,因此仅在关闭SessionFactory时会销毁它(通常是在应用程序关闭时)。 第二级缓存主要基于实体,尽管它也支持可选的查询缓存解决方案。

默认情况下,二级缓存是禁用的,要激活它,我们必须设置以下Hibernate属性:

properties.put("hibernate.cache.use_second_level_cache", Boolean.TRUE.toString());
properties.put("hibernate.cache.region.factory_class", "org.hibernate.cache.ehcache.EhCacheRegionFactory");

一旦将hibernate.cache.use_second_level_cache属性设置为true , RegionFactory将定义第二级缓存实现提供程序,并且hibernate.cache.region.factory_class配置是必需的。

要启用实体级缓存,我们需要如下注释可缓存实体:

@Entity
@org.hibernate.annotations.Cache(usage = CacheConcurrencyStrategy.NONSTRICT_READ_WRITE)

JPA还定义了@Cacheable批注,但它不支持在实体级别设置并发策略

实体加载流程

每当要加载实体时, 都会触发LoadEevent并由 DefaultLoadEventListener对其进行如下处理:

Object entity = loadFromSessionCache( event, keyToLoad, options );
if ( entity == REMOVED_ENTITY_MARKER ) {LOG.debug("Load request found matching entity in context, but it is scheduled for removal;returning null" );return null;
}
if ( entity == INCONSISTENT_RTN_CLASS_MARKER ) {LOG.debug("Load request found matching entity in context, but the matched entity was ofan inconsistent return type;returning null");return null;
}
if ( entity != null ) {if ( traceEnabled ) {LOG.tracev("Resolved object in "+ "session cache: {0}",MessageHelper.infoString( persister,event.getEntityId(),event.getSession().getFactory() ));}return entity;
}entity = loadFromSecondLevelCache( event, persister, options );
if ( entity != null ) {if ( traceEnabled ) {LOG.tracev("Resolved object in "+ "second-level cache: {0}",MessageHelper.infoString( persister,event.getEntityId(),event.getSession().getFactory() ));}
}
else {if ( traceEnabled ) {LOG.tracev("Object not resolved in "+ "any cache: {0}",MessageHelper.infoString( persister,event.getEntityId(),event.getSession().getFactory() ));}entity = loadFromDatasource( event, persister, keyToLoad, options );
}

始终首先检查该会话,因为它可能已经包含一个受管实体实例。 在访问数据库之前,已对二级缓存进行了验证,因此其主要目的是减少数据库访问的次数。

二级缓存内部

每个实体都存储为CacheEntry ,并且实体水合状态用于创建缓存条目值。

补水

在Hibernate命名法中, 水化是将JDBC ResultSet转换为原始值数组时:

final Object[] values = persister.hydrate(rs, id, object, rootPersister, cols, eagerPropertyFetch, session
);

水合状态作为EntityEntry对象保存在当前运行的持久性上下文中 ,该对象封装了加载时实体快照。 然后通过以下方式使用水合状态:

  • 默认的脏检查机制 ,该机制将当前实体数据与加载时快照进行比较
  • 第二级缓存,其缓存项是根据加载时实体快照构建的

反向操作称为脱水 ,它将实体状态复制到INSERTUPDATE语句中。

二级缓存元素

尽管Hibernate允许我们操纵实体图,但是二级缓存使用反汇编的水合状态代替:

final CacheEntry entry = persister.buildCacheEntry( entity, hydratedState, version, session );

水合状态在存储在CacheEntry中之前先进行分解:

this.disassembledState = TypeHelper.disassemble(state, persister.getPropertyTypes(),persister.isLazyPropertiesCacheable() ? null : persister.getPropertyLaziness(),session, owner
);

从以下实体模型图开始:

后注释详细信息第二级缓存

我们将插入以下实体:

Post post = new Post();
post.setName("Hibernate Master Class");post.addDetails(new PostDetails());
post.addComment(new Comment("Good post!"));
post.addComment(new Comment("Nice post!"));session.persist(post);

现在,我们将检查每个单独的实体缓存元素。

邮政实体有一个一对多关联的注释实体和逆一个-to-one关联到PostDetails:

@OneToMany(cascade = CascadeType.ALL, mappedBy = "post")
private List<Comment> comments = new ArrayList<>();@OneToOne(cascade = CascadeType.ALL, mappedBy = "post", optional = true)
private PostDetails details;

提取Post实体时:

Post post = (Post) session.get(Post.class, 1L);

关联的缓存元素如下所示:

key = {org.hibernate.cache.spi.CacheKey@3855}key = {java.lang.Long@3860} "1"type = {org.hibernate.type.LongType@3861} entityOrRoleName = {java.lang.String@3862} "com.vladmihalcea.hibernate.masterclass.laboratory.cache.SecondLevelCacheTest$Post"tenantId = nullhashCode = 31
value = {org.hibernate.cache.spi.entry.StandardCacheEntryImpl@3856}disassembledState = {java.io.Serializable[3]@3864} 0 = {java.lang.Long@3860} "1"1 = {java.lang.String@3865} "Hibernate Master Class"subclass = {java.lang.String@3862} "com.vladmihalcea.hibernate.masterclass.laboratory.cache.SecondLevelCacheTest$Post"lazyPropertiesAreUnfetched = falseversion = null

CacheKey包含实体标识符,而CacheEntry包含实体分解的水合状态。

Post条目缓存值由name列和id组成 ,它们由一对多 Comment关联设置。

一对多关联或反向一对一关联都没有嵌入Post CacheEntry中

PostDetails实体主键是引用相关帖子实体的主键 ,因此具有与邮政实体一到一对一的关联。

@OneToOne
@JoinColumn(name = "id")
@MapsId
private Post post;

提取PostDetails实体时:

PostDetails postDetails = (PostDetails) session.get(PostDetails.class, 1L);

第二级缓存生成以下缓存元素:

key = {org.hibernate.cache.spi.CacheKey@3927}key = {java.lang.Long@3897} "1"type = {org.hibernate.type.LongType@3898} entityOrRoleName = {java.lang.String@3932} "com.vladmihalcea.hibernate.masterclass.laboratory.cache.SecondLevelCacheTest$PostDetails"tenantId = nullhashCode = 31
value = {org.hibernate.cache.spi.entry.StandardCacheEntryImpl@3928}disassembledState = {java.io.Serializable[2]@3933} 0 = {java.sql.Timestamp@3935} "2015-04-06 15:36:13.626"subclass = {java.lang.String@3932} "com.vladmihalcea.hibernate.masterclass.laboratory.cache.SecondLevelCacheTest$PostDetails"lazyPropertiesAreUnfetched = falseversion = null

由于实体标识符嵌入在CacheKey中 ,因此反汇编状态仅包含createdOn实体属性。

Comment实体与Post 具有多对一关联:

@ManyToOne
private Post post;

当我们获取评论实体时:

Comment comments = (Comment) session.get(Comment.class, 1L);

Hibernate生成以下二级缓存元素:

key = {org.hibernate.cache.spi.CacheKey@3857}key = {java.lang.Long@3864} "2"type = {org.hibernate.type.LongType@3865} entityOrRoleName = {java.lang.String@3863} "com.vladmihalcea.hibernate.masterclass.laboratory.cache.SecondLevelCacheTest$Comment"tenantId = nullhashCode = 62
value = {org.hibernate.cache.spi.entry.StandardCacheEntryImpl@3858}disassembledState = {java.io.Serializable[2]@3862} 0 = {java.lang.Long@3867} "1"1 = {java.lang.String@3868} "Good post!"subclass = {java.lang.String@3863} "com.vladmihalcea.hibernate.masterclass.laboratory.cache.SecondLevelCacheTest$Comment"lazyPropertiesAreUnfetched = falseversion = null

反汇编状态包含Post.id 外键引用和检查列,因此镜像了关联的数据库表定义。

结论

第二级缓存是关系数据缓存,因此它以规范化形式存储数据,并且每个实体更新仅影响一个缓存条目。 无法读取整个实体图,因为在第二级缓存条目中未实现实体关联。

聚合实体图以使写入操作复杂化为代价,为读取操作提供了更好的性能。 如果缓存的数据未规范化并散布在各种聚合模型中,则实体更新将不得不修改多个缓存项,从而影响写入操作性能。

由于它反映了基础关系数据,因此二级缓存提供了各种并发策略机制,因此我们可以平衡读取性能和强大的一致性保证。

  • 代码可在GitHub上获得 。

翻译自: https://www.javacodegeeks.com/2015/04/how-does-hibernate-store-second-level-cache-entries.html

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

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

相关文章

file协议访问linux,Mozilla Firefox for Android 'file'协议未授权访问漏洞(CVE-2014-1501)

发布日期&#xff1a;2014-03-18更新日期&#xff1a;2014-04-02受影响系统&#xff1a;Mozilla Firefox < 28.0描述&#xff1a;--------------------------------------------------------------------------------BUGTRAQ ID: 66424CVE(CAN) ID: CVE-2014-1501Firefox是…

DrJava试用笔记

安装方便&#xff1a;只要配好JAVA_HOME&#xff0c;用java -jar drjava-stable-20120818-r5686.jar即可启动&#xff0c;算是绿色软件&#xff1b; 特色功能&#xff1a;交互式命令行&#xff0c;可以在调试程序时改变变量值&#xff0c;很方便&#xff1b; 编辑功能比较弱&…

dcdc芯片效率不高的原因_半导体厂商如何做芯片的出厂测试?

本文来源于知乎&#xff0c;已获作者授权&#xff0c;谢谢。作者&#xff1a;温戈链接&#xff1a;https://www.zhihu.com/question/20584576/answer/1538640891知乎网友提问&#xff1a;半导体厂商如何做芯片的出厂测试&#xff1f;例如 Intel 的 CPU、手机处理器&#xff0c;…

在运行时更新代码(已Spring解密)

当从编译到部署再到测试的开发周期花费太长时间时&#xff0c;人们希望能够及时替换正在运行的代码&#xff0c;而无需重新启动应用程序服务器并等待部署完成。 在这种情况下&#xff0c;像JRebel这样的商业解决方案或像Grails这样的开源框架就可以提供帮助。 JVM不支持在运行…

魅族android n内测报名,不再万年Android 5.0! Flyme安卓N内测招募开启

科客点评&#xff1a;恰逢Flyme五周年庆&#xff0c;这算的是给煤油们最大的礼物。近日&#xff0c;魅族Flyme系统非常活跃&#xff0c;为国内友商操碎了心&#xff0c;为此适配了一众友商热门机型&#xff0c;刷了不少存在感&#xff0c;但这显然不是魅族要搞的“大事情”。6月…

Android AudioTrack/AudioRecord -wav文件读取3

下面是一个网上一个大神写的,在公司测过了,还不错. 还可以写一个构造函数: initReader(InputStream is){ fis new FileInputStream(is); bis new BufferedInputStream(fis); }eg:call it as following : InputStream isActivity.getResource().openRawResource(); InitRe…

db2数据库连接数 linux_介绍一款数据库管理工具DBeaver

之前连接MySQL一直使用的是navicate&#xff0c;挺好用的&#xff0c;不过是个付费软件&#xff0c;一直想找一款免费开源的软件来替代。今天偶然间发现DBeaver&#xff0c;这是一款基于java开发的数据库工具&#xff0c;而且可以支持Windows、Linux、MacOS多个平台&#xff0c…

jqgrid mvc_jqGrid,REST,AJAX和Spring MVC集成

jqgrid mvc两年多以前&#xff0c;我写了一篇关于如何在Struts2中实现优雅的CRUD的文章。 实际上&#xff0c;我必须就该主题写两篇文章&#xff0c;因为该主题如此广泛。 今天&#xff0c;我采用了一套更为流行的&#xff0c;完善的框架和库&#xff0c;采用了更为轻量级的现代…

android view getwidth 0,Android中View.getWidth()和View.getMeasuredWidth()的区别

一。也許很多童鞋對getWidth()和getMeasuredWidth()的用法有很多的不解&#xff0c;這兩者之間有什麼樣的不同呢&#xff0c;網上也有各種不同的版本&#xff0c;但大多數都大同小異&#xff0c;從這個地方CtrlC,到另一個地方CtrlV,沒有把問題說透&#xff0c;也有一部分文章誤…

微信利用PHP创建自定义菜单的方法

在使用通用接口前&#xff0c;你需要做以下两步工作&#xff1a;1.拥有一个微信公众账号&#xff0c;并获取到appid和appsecret&#xff08;在公众平台申请内测资格&#xff0c;审核通过后可获得&#xff09;2.通过获取凭证接口获取到access_token注意&#xff1a;access_token…

ChronicleMap –具有堆外内存的Java体系结构

我的上一篇文章是在几周前写的&#xff0c;在收到一些有效的反馈后&#xff0c;我想澄清几点&#xff0c;作为本文的序言。 “ 使用零垃圾创建数百万个对象 ”的主要收获应该是&#xff0c;使用Chronicle&#xff0c;在编写Java程序时&#xff0c;您不会“局限于”使用jvm分配…

HTML滚动条S默认最小值,css修改滚动条默认样式

html代码:这是内容111这里是内容222这里是内容333css代码:.inner{width: 265px;height: 400px;position: absolute;top: 33px;left: 13px;/*cursor: pointer;*/overflow:hidden;}.innerbox{overflow-x: hidden;overflow-y: auto;color: #000;font-size: .7rem;font-family: &qu…

下列不属于html5语义元素,HTML5 新的语义元素

HTML5 提供了新的语义元素来明确一个Web页面的不同部分:HTML5中新的语义元素HTML5 元素标签定义文档中的节(section、区段)。比如章节、页眉、页脚或文档中的其他部分。根据W3C HTML5文档: section 包含了一组内容及其标题。WWFThe World Wide Fund for Nature (WWF) is....HTM…

【Android Developers Training】 81. 解析XML数据

注&#xff1a;本文翻译自Google官方的Android Developers Training文档&#xff0c;译者技术一般&#xff0c;由于喜爱安卓而产生了翻译的念头&#xff0c;纯属个人兴趣爱好。 原文链接&#xff1a;http://developer.android.com/training/basics/network-ops/xml.html 可扩展…

java核心面试_不正确的核心Java面试答案

java核心面试总览 在Internet上&#xff0c;Java面试问题和答案从一个网站复制到另一个网站。 这可能意味着错误或过时的答案可能永远不会得到纠正。 这是一些不太正确或已经过时的问题和答案。 即是Java 5.0之前的版本。 每个提供的问题后都有两个部分。 斜体的第一部分指示…

outlook自动保存html,当创建一个新的HTML电子邮件时保持默认的Outlook格式

我想创建一个简单的脚本来创建一个HTML消息&#xff0c;并且我想保留尽可能多的默认值。当创建一个新的HTML电子邮件时保持默认的Outlook格式在我的情况下&#xff0c;当我使用Home创建一个新邮件->新邮件时&#xff0c;它总是会创建一个默认字体[Calibri 11]&#xff0c;格…

干加个偏旁可以变成什么字_面试官:“干”字加一笔,变成什么字?回答王和午字不对...

随着大学生的增多&#xff0c;如今的求职者进入职场&#xff0c;想到一份心仪的工作&#xff0c;最让人头疼的就是面试&#xff0c;越来越多的企业都需要全能型的人才&#xff0c;从而在面试的时候不仅要考核专业知识&#xff0c;面试官还要费尽心思出各种各样的题来考验求职者…

Oracle研学-查询

学自B站黑马程序员 1.单表查询 //查询水表编号为 30408 的业主记录 select * from T_OWNERS where watermeter30408 //查询业主名称包含“刘”的业主记录 select * from t_owners where name like %刘% //查询业主名称包含“刘”的并且门牌号包含 5 的业主记录 select * from…

国际站html代码,国际站必须看得懂的HTML代码

国际站必须看得懂的HTML代码國産〇〇柒大家每天都忙着找关键词&#xff0c;忙着写标题&#xff0c;忙着做各种的优化。目的就是想把自己的产品排名到前面&#xff0c;获得更多的曝光&#xff0c;带来更多的询盘。在这个过程中我们是客服同事也是一名搜索优化人员&#xff0c;但…

phoengap–node+websocket在线聊天室

该实验项目基于&#xff1a; phonegapnodewebsocket可以应用于android 和 ios平台。 已经测试通过。以下是测试的图&#xff1a; 首先是用node 架设服务器。 基本上都node 基于websocket的。 主要是对message做处理和判断来进行输出和逻辑处理 而客户都&#xff0c;由于android…