休眠NONSTRICT_READ_WRITE CacheConcurrencyStrategy如何工作

介绍

在我以前的文章中 ,我介绍了READ_ONLY CacheConcurrencyStrategy ,这是不可变实体图的显而易见的选择。 当缓存的数据可变时,我们需要使用读写缓存策略,本文将介绍NONSTRICT_READ_WRITE二级缓存的工作方式。

内部运作

提交Hibernate事务后,将执行以下操作序列:

nonstrictreadwritecacheconcurrencystrategy3

首先,在刷新期间,在提交数据库事务之前,缓存无效:

  1. 当前的Hibernate事务 (例如JdbcTransaction , JtaTransaction )已刷新
  2. DefaultFlushEventListener执行当前的ActionQueue
  3. EntityUpdateAction调用EntityRegionAccessStrategy的更新方法
  4. NonStrictReadWriteEhcacheCollectionRegionAccessStrategy将从基础EhcacheEntityRegion中删除缓存条目

提交数据库事务后,将再次删除缓存条目:

  1. 完成回调后当前的Hibernate Transaction被调用
  2. 当前会话将此事件传播到其内部ActionQueue
  3. EntityUpdateActionEntityRegionAccessStrategy上调用afterUpdate方法
  4. NonStrictReadWriteEhcacheCollectionRegionAccessStrategy调用基础EhcacheEntityRegion上的remove方法

不一致警告

NONSTRICT_READ_WRITE模式不是“ 写式”缓存策略,因为缓存条目无效,而不是被更新。 缓存无效化与当前数据库事务不同步。 即使关联的Cache区域条目两次无效(在事务完成之前和之后),当缓存和数据库可能分开时,仍然还有一个很小的时间窗口。

以下测试将演示此问题。 首先,我们将定义Alice事务逻辑:

doInTransaction(session -> {LOGGER.info("Load and modify Repository");Repository repository = (Repository)session.get(Repository.class, 1L);assertTrue(getSessionFactory().getCache().containsEntity(Repository.class, 1L));repository.setName("High-Performance Hibernate");applyInterceptor.set(true);
});endLatch.await();assertFalse(getSessionFactory().getCache().containsEntity(Repository.class, 1L));doInTransaction(session -> {applyInterceptor.set(false);Repository repository = (Repository)session.get(Repository.class, 1L);LOGGER.info("Cached Repository {}", repository);
});

爱丽丝加载存储库实体,并在她的第一个数据库事务中对其进行修改。
为了在Alice准备提交时产生另一个并发事务,我们将使用以下Hibernate Interceptor :

private AtomicBoolean applyInterceptor = new AtomicBoolean();private final CountDownLatch endLatch = new CountDownLatch(1);private class BobTransaction extends EmptyInterceptor {@Overridepublic void beforeTransactionCompletion(Transaction tx) {if(applyInterceptor.get()) {LOGGER.info("Fetch Repository");assertFalse(getSessionFactory().getCache().containsEntity(Repository.class, 1L));executeSync(() -> {Session _session = getSessionFactory().openSession();Repository repository = (Repository) _session.get(Repository.class, 1L);LOGGER.info("Cached Repository {}", repository);_session.close();endLatch.countDown();});assertTrue(getSessionFactory().getCache().containsEntity(Repository.class, 1L));}}
}

运行此代码将生成以下输出:

[Alice]: Load and modify Repository
[Alice]: select nonstrictr0_.id as id1_0_0_, nonstrictr0_.name as name2_0_0_ from repository nonstrictr0_ where nonstrictr0_.id=1
[Alice]: update repository set name='High-Performance Hibernate' where id=1[Alice]: Fetch Repository from another transaction
[Bob]: select nonstrictr0_.id as id1_0_0_, nonstrictr0_.name as name2_0_0_ from repository nonstrictr0_ where nonstrictr0_.id=1
[Bob]: Cached Repository from Bob's transaction Repository{id=1, name='Hibernate-Master-Class'}[Alice]: committed JDBC Connection[Alice]: select nonstrictr0_.id as id1_0_0_, nonstrictr0_.name as name2_0_0_ from repository nonstrictr0_ where nonstrictr0_.id=1
[Alice]: Cached Repository Repository{id=1, name='High-Performance Hibernate'}
  1. Alice获取存储库并更新其名称
  2. 调用定制的Hibernate Interceptor并启动Bob的事务
  3. 由于存储库已从缓存中逐出,因此Bob将使用当前数据库快照加载第二级缓存
  4. Alice事务已提交,但是现在缓存包含Bob刚刚加载的先前数据库快照
  5. 如果第三位用户现在将获取存储库实体,那么他还将看到与当前数据库快照不同的陈旧实体版本。
  6. 提交Alice事务后,将再次逐出Cache条目,并且任何后续实体加载请求都将使用当前数据库快照填充Cache

过时的数据与丢失的更新

当数据库和二级缓存可能不同步时, NONSTRICT_READ_WRITE并发策略会引入一个很小的不一致窗口。 尽管这听起来可能很糟糕,但实际上,即使我们不使用二级缓存,也应始终设计应用程序来应对这些情况。 Hibernate通过其事务性的后写式第一级缓存提供应用程序级可重复读取,并且所有托管实体都将变得过时。 在将实体加载到当前的持久性上下文中之后 ,另一个并发事务可能会对其进行更新,因此,我们需要防止陈旧的数据升级为丢失的更新 。

乐观并发控制是处理长时间对话中丢失的更新的有效方法,并且该技术还可以缓解NONSTRICT_READ_WRITE不一致问题。

结论

NONSTRICT_READ_WRITE并发策略是大多数只读应用程序的不错选择(如果由乐观锁定机制支持)。 对于写密集型方案,缓存无效机制将增加缓存未命中率 ,因此使该技术效率低下。

  • 代码可在GitHub上获得 。

翻译自: https://www.javacodegeeks.com/2015/05/how-does-hibernate-nonstrict_read_write-cacheconcurrencystrategy-work.html

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

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

相关文章

mysql用大白话解释_Java基础--2021Java面试题系列教程--大白话解读

前言序言再高大上的框架,也需要扎实的基础才能玩转,高频面试问题更是基础中的高频实战要点。适合阅读人群Java 学习者和爱好者,有一定工作经验的技术人,准面试官等。阅读建议本教程是系列教程,包含 Java 基础&#xff…

Android开源之行之走进zxing,轻松实现二维码扫描(二)

对于Zxing开源项目的简化上文已给出,源码经过测试且不断修改。众所周知,Zxing项目的扫描是横向的,这么引用的用户体验确实不好;然而盲目的修改会出现拉伸以及样本采集的偏离。所以这里说一下如何将横屏修改为竖屏扫描 解决办法引用…

mysql二进制大文件_Mysql实例Mysql LONGTEXT 类型存储大文件(二进制也可以) (修改+调试+整理)...

《Mysql实例Mysql LONGTEXT 类型存储大文件(二进制也可以) (修改调试整理)》要点:本文介绍了Mysql实例Mysql LONGTEXT 类型存储大文件(二进制也可以) (修改调试整理),希望对您有用。如果有疑问,可以联系我们。#include "stdafx.h"/…

阿里云mysql创建多个用户_阿里云MySQL创建指定用户访问指定表

欢迎大家关注我的公众号,有问题可以及时和我交流。1.首先进入到root用户环境mysql -uroot -p输入自己的root密码登录。登录成功之后如果表之前已经存在的话就不需要创建,如果表不存在的话使用创建表命令创建。create database table;2.给用户…

自定义实现moveable button

实现的效果图: 自定义MVButton,继承自UIButton. 属性声明如下: property (nonatomic) CGPoint beginPoint; property (nonatomic) BOOL dragEnable;//自定义button对触摸事件进行响应- (void)touchesBegan:(NSSet *)touches withEvent:(UI…

jOOQ星期二:Vlad Mihalcea深入了解SQL和Hibernate

欢迎来到jOOQ Tuesdays系列。 在本系列中,我们每隔一个月的第三个星期二发布一篇文章,从jOOQ的角度采访我们发现该行业令人兴奋的人。 这包括从事SQL,Java,开放源代码以及其他各种相关主题的人员。 我们很高兴在第三版中与Vlad …

GitHub初次使用记录(一)

1、从GitHub上克隆或者复制别人的档案库: 克隆档案库时需要打开本地Git客户端(比如GitHub for Windows 和 GitExtesnsion )操作。 下面是用GitExtension克隆档案库: 转载于:https://www.cnblogs.com/lxf1117/p/4140048.html

java集成_Java继承

一.继承1.简介:特点:利于代码复用;缩短开发周期。注:子类不能直接访问父类的私有属性满足“A is a B”的关系就可以形成继承关系例:父类:1 packagecom.swpu.animals;23 public classAnimal {4 //属性5 priv…

java猜数字小游戏_Java实现简单猜数字小游戏

本文实例为大家分享了Java实现猜数字游戏的具体代码,供大家参考,具体内容如下完成猜数字游戏需要实现以下几点:获得一个随机数作为“答案数”; 输入数字,与“答案数”作比较(判断大了,小了,相等…

java软件工程师 英文简历_2017java程序员英文简历范文

2017java程序员英文简历范文简历写完以后,再检查一下你的简历是否回答了以下问题:它是否清楚并能够让雇主尽快知道你的能力?是否写清了你的能力?是否写清了你要求这份工作的.基础?有东西可删除吗?尽力完善你的简历直到最好。2017java程序员英文简历范…

写给java web一年左右工作经验的人

摘要 大学就开始学习web,磕磕绊绊一路走过来,当中得到过开源社区很多的帮助,总结了这些年来的技术积累,回馈给开源社区。 ps:图片都是从网上盗。。。感谢原作者。 ps:文字千真万确都是我自己写的。 在此&am…

FlexyPool如何支持Dropwizard Metrics包重命名

介绍 FlexyPool严重依赖Dropwizard (以前是Codahale)度量标准来监视连接池的使用情况 。 集成到Dropwizard中后,程序包名称必然会被重命名 。 因此,4.0.0版本将使用io.dropwizard.metrics软件包名称代替com.codahale.metrics 。 …

嵌入式Linux学习笔记

一 嵌入式系统定义: 应用于特定环境的硬件体系。 二 两样非常重要的能力: 1. 掌握各种新概念的能力 2. 调试的能力( 包括软件, 硬件 ) 三 需要的基础知识: 1. 操作系统理论基础 2. 数据结构 3. C,C编程语言 4. 汇编语言 5. Linux基…

java string 内存占用_JVM系列之:String,数组和集合类的内存占用大小

简介之前的文章中,我们使用JOL工具简单的分析过String,数组和集合类的内存占用情况,这里再做一次更详细的分析和介绍,希望大家后面再遇到OOM问题的时候不再抱头痛哭,而是可以有章可循,开始吧。数组先看下JOL的代码和输…

maven osgi_OSGi将Maven与Equinox结合使用

maven osgi很长时间以来,我一直在努力理解OSGi的真正含义。 它已经存在很长时间了,但是没有多少人意识到这一点。 它被炒作是一种非常复杂的技术。 这是我为所有Java开发人员简化的尝试。 简而言之, OSGi是一组规范,这些规范支持模…

python中、文件最重要的功能是( )和接收数据_Python基础语法14个知识点大串讲

来源:Python数据之道Python基础语法大串讲Python 是一门面向对象的编程语言,相信这篇文章对于初学者而言应该会有一个比较大的帮助,下面我们将 Python 中常用的基础语法和函数做了一个汇总,满满的干货,供大家学习。1、…

hadoop简单介绍_Hadoop:简单介绍

hadoop简单介绍什么是Hadoop: Hadoop是用Java编写的框架,用于在大型商品硬件群集上运行应用程序,并具有类似于Google File System和MapReduce的功能 。 HDFS是一个高度容错的分布式文件系统,与Hadoop一样,旨在部署在低…

java mvc 案例_springmvc经典案例

本想自己写一下总结,但是发现一篇好文,转发一下,日后自己再做补充;感谢Sunnier,引自:https://www.cnblogs.com/sunniest/p/4555801.htmlSpringMVC学习笔记----一、SpringMVC基础入门,创建一个He…

java泛型方法无参_从头再来:Java泛型(开发必须知道的)

Java泛型老规矩,测试一下,下面的程序能否正常运行?为什么?开头测试题泛型就是实现了参数化类型,也就是代码可以适用于多种类型。泛型是在编译期检查的,在编译期检查类型是否安全。我认为泛型最有用的就是和…

几种常见模式识别算法整理和总结

这学期选了门模式识别的课。发现最常见的一种情况就是,书上写的老师ppt上写的都看不懂,然后绕了一大圈去自己查资料理解,回头看看发现,Ah-ha,原来本质的原理那么简单,自己一開始仅仅只是被那些看似formidab…