休眠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项目的扫描是横向的,这么引用的用户体验确实不好;然而盲目的修改会出现拉伸以及样本采集的偏离。所以这里说一下如何将横屏修改为竖屏扫描 解决办法引用…

mdb批量导入mysql_快速将 access 用的 mdb 文件导入到 mysql 里

下载链接:http://www.bullzip.com/download/a2m/msa2mys_5_4_0_274.zipAccess To MySQLAccess to MySQL is a small program that will convert Microsoft Access Databases to MySQL.Wizard interface.Transfer data directly from one server to another.Create a…

动画

1.UIVIew 1.1 动画块(改变背景颜色和移动) static BOOL flagYES; //开始动画 [UIView beginAnimations:nil context:nil]; //运动的时间 [UIView setAnimationDuration:2.f]; //延时启动 [UIView setAnimationDelay:2.f]; //速度曲线 [UIView setAnimationCurve:UIViewAnima…

app engine_Google App Engine:在您自己的域中托管应用程序

app engine在Google App Engine中创建新应用程序时,您将获得一个域名“ yourapp.appspot.com”。 但是,谁会想要以这样的后缀托管他们的应用程序(除非您喜欢它!)? 为了改善您的应用程序品牌,最好…

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

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

bzoj2243 [SDOI2011]染色

Description 给定一棵有n个节点的无根树和m个操作,操作有2类: 1、将节点a到节点b路径上所有点都染成颜色c; 2、询问节点a到节点b路径上的颜色段数量(连续相同颜色被认为是同一段),如“112221”由3段组成&am…

阿里云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 …

python编程序列类型_python序列类型种类详解

python序列类型包括哪三种python序列类型包括:列表、元组、字典列表:有序可变序列创建:userlist [1,2,3,4,5,6]修改:userlist[5] 999添加:userlist.append(777)删除:userlist.remove(4) 或者 del(userlis…

GitHub初次使用记录(一)

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

mysql中逗号前的字符串_MySql逗号拼接字符串查询的两种方法

下面两个函数的使用和FIND_IN_SET一样,使用时只需要把FIND_IN_SET换成FIND_PART_IN_SET或FIND_ALL_PART_IN_SET例如某字段里是为1,2,3,4,5使用方法:第一种,传入1,3,6 可以查出来 select * from XXX where FIND_PART_IN_SET(1,3,6,1,2,3,4,5)第二种,传入1,3,6 查不出来 select *…

使用Maven,Jetty和Tomcat在嵌入式容器中运行Java Web应用程序

在开发Java Web应用程序时,从“真实”环境中获得快速反馈非常实用。 在本文中,我将探讨如何在嵌入式容器Jetty或Tomcat中运行带有Maven的Java Web应用程序。 在Podcastpedia.org网站的支持下,我将展示如何配置它们以开发podcastpedia项目。 …

Linux下查看文件和文件夹大小

当磁盘大小超过标准时会有报警提示,这时如果掌握df和du命令是非常明智的选择。 df可以查看一级文件夹大小、使用比例、档案系统及其挂入点,但对文件却无能为力。 du可以查看文件及文件夹的大小。 两者配合使用,非常有效。比如用df查看哪个…

moosefs mysql_moosefs搭建与应用

moosefs搭建与应用MooseFS简介:MooseFS是一个具备冗余容错功能的分布式网络文件系统,它将数据分别存放在多个物理服务器单独磁盘或分区上,确保一份数据有多个备份副本。因此MooseFS是一中很好的分布式存储。接下来我们通过搭建moosefs&#x…

Audio Offload

Audio Offload 音频分载,是系统将音频分载到声卡硬件进行分载处理的功能。从Windows 8开始,音频的硬件加速和分载处理又回来了。为什么说又回来了呢? 因为声卡自创通公司发明开始,相当长一段时间都是由声卡独立完成所有音频处理的…

mysql数据库迁徙_mysql数据迁徙详解

数据迁徙是每个后端都会遇到的工作之一&#xff0c;本文介绍了一些常见的数据迁徙方法与工具mysqldump&#xff1a;数据结构不变的数据迁徙导出数据 mysqldump -u root -p DATABASE_NAME table_name > dump.sql恢复数据 mysql -u root -p DATABESE_NAME < dump.sql或者连…

junit-4.9.jar_JUnit 4.9(测试版3)中的规则

junit-4.9.jar不久前&#xff0c; David Saff宣布了JUnit 4.9的beta版 。 因此&#xff0c;我认为现在是研究该版本中的新增功能的好时机。 JUnit领域中最有用的创新之一是Rule。 我在这里写了有关规则的文章 。 我在这里写了有关JUnit规则的用例 。 规则很棒。 借助JUnit 4.9&…

封装js千分位加逗号和删除逗号

//封装js千分位加逗号和删除逗号alert( format(2545678754.020001) ) //2,545,678,754.03alert( format(-2545678754.020001) ) //-2,545,678,754.02alert( format(2545678754.000000000009) ); //当值很长的时候会出现数字被截取的问题alert( delformat(2,545,678,75…