Hibernate READ_ONLY CacheConcurrencyStrategy如何工作

介绍

正如我前面所解释的 ,企业的高速缓存需要勤奋。 由于数据在数据库( 记录系统 )和缓存层之间重复,因此我们需要确保两个单独的数据源不会分开。

如果缓存的数据是不可变的(数据库和缓存都无法修改它),我们可以安全地对其进行缓存,而不必担心任何一致性问题。 只读数据始终是应用程序级缓存的理想选择,可以在不放松一致性保证的情况下提高读取性能。

只读二级缓存

为了测试只读二级缓存策略,我们将使用以下域模型:

存储库提交更改只读缓存并发策略

存储库是根实体,是任何Commit实体的父代。 每个提交都有一个“ 更改”组件(可嵌入的值类型)列表。

所有实体都缓存为只读元素:

@org.hibernate.annotations.Cache(usage = CacheConcurrencyStrategy.READ_ONLY
)

持久实体

只读二级缓存使用一种直读缓存策略,在获取时会缓存实体。

doInTransaction(session -> {Repository repository = new Repository("Hibernate-Master-Class");session.persist(repository);
});

当一个实体持久化时,只有数据库包含该实体的副本。 首次获取实体时,记录系统将传递到缓存层。

@Test
public void testRepositoryEntityLoad() {LOGGER.info("Read-only entities are read-through");doInTransaction(session -> {Repository repository = (Repository) session.get(Repository.class, 1L);assertNotNull(repository);});doInTransaction(session -> {LOGGER.info("Load Repository from cache");session.get(Repository.class, 1L);});
}

此测试生成输出:

--Read-only entities are read-throughSELECT readonlyca0_.id   AS id1_2_0_,readonlyca0_.NAME AS name2_2_0_
FROM   repository readonlyca0_
WHERE  readonlyca0_.id = 1 --JdbcTransaction - committed JDBC Connection--Load Repository from cache--JdbcTransaction - committed JDBC Connection

将实体加载到二级缓存后,缓存将为随后的所有调用提供服务,从而绕过数据库。

更新实体

只读缓存条目不允许更新。 任何此类尝试最终都会引发异常:

@Test
public void testReadOnlyEntityUpdate() {try {LOGGER.info("Read-only cache entries cannot be updated");doInTransaction(session -> {Repository repository = (Repository) session.get(Repository.class, 1L);repository.setName("High-Performance Hibernate");});} catch (Exception e) {LOGGER.error("Expected", e);}
}

运行此测试将生成以下输出:

--Read-only cache entries cannot be updatedSELECT readonlyca0_.id   AS id1_2_0_,readonlyca0_.NAME AS name2_2_0_
FROM   repository readonlyca0_
WHERE  readonlyca0_.id = 1 UPDATE repository
SET    NAME = 'High-Performance Hibernate'
WHERE  id = 1 --JdbcTransaction - rolled JDBC Connection--ERROR Expected
--java.lang.UnsupportedOperationException: Can't write to a readonly object

因为只读缓存实体实际上是不可变的,所以最好将它们赋予 Hibernate特有的@Immutable批注。

删除实体

同时删除关联的实体时,也会删除只读缓存条目:

@Test
public void testReadOnlyEntityDelete() {LOGGER.info("Read-only cache entries can be deleted");doInTransaction(session -> {Repository repository = (Repository) session.get(Repository.class, 1L);assertNotNull(repository);session.delete(repository);});doInTransaction(session -> {Repository repository = (Repository) session.get(Repository.class, 1L);assertNull(repository);});
}

生成以下输出:

--Read-only cache entries can be deletedSELECT readonlyca0_.id   AS id1_2_0_,readonlyca0_.NAME AS name2_2_0_
FROM   repository readonlyca0_
WHERE  readonlyca0_.id = 1;DELETE FROM repository
WHERE  id = 1--JdbcTransaction - committed JDBC ConnectionSELECT readonlyca0_.id   AS id1_2_0_,readonlyca0_.NAME AS name2_2_0_
FROM   repository readonlyca0_
WHERE  readonlyca0_.id = 1; --JdbcTransaction - committed JDBC Connection

PersistenceContext使移除 实体状态转换入队,并且在刷新时 ,数据库和二级缓存都将删除关联的实体记录。

集合缓存

提交实体具有变更组件的集合。

@ElementCollection
@CollectionTable(name="commit_change",joinColumns=@JoinColumn(name="commit_id")
)
private List<Change> changes = new ArrayList<>();

尽管Commit实体作为只读元素进行缓存,但第二级缓存将忽略Change集合。

@Test
public void testCollectionCache() {LOGGER.info("Collections require separate caching");doInTransaction(session -> {Repository repository = (Repository) session.get(Repository.class, 1L);Commit commit = new Commit(repository);commit.getChanges().add(new Change("README.txt", "0a1,5..."));commit.getChanges().add(new Change("web.xml", "17c17..."));session.persist(commit);});doInTransaction(session -> {LOGGER.info("Load Commit from database");Commit commit = (Commit) session.get(Commit.class, 1L);assertEquals(2, commit.getChanges().size());});doInTransaction(session -> {LOGGER.info("Load Commit from cache");Commit commit = (Commit) session.get(Commit.class, 1L);assertEquals(2, commit.getChanges().size());});
}

运行此测试将生成以下输出:

--Collections require separate cachingSELECT readonlyca0_.id   AS id1_2_0_,readonlyca0_.NAME AS name2_2_0_
FROM   repository readonlyca0_
WHERE  readonlyca0_.id = 1;INSERT INTO commit(id, repository_id)
VALUES      (DEFAULT, 1);INSERT INTO commit_change(commit_id, diff, path)
VALUES      (1, '0a1,5...', 'README.txt');		 INSERT INTO commit_change(commit_id, diff, path)
VALUES      (1, '17c17...', 'web.xml');--JdbcTransaction - committed JDBC Connection--Load Commit from databaseSELECT readonlyca0_.id   AS id1_2_0_,readonlyca0_.NAME AS name2_2_0_
FROM   repository readonlyca0_
WHERE  readonlyca0_.id = 1;SELECT changes0_.commit_id AS commit_i1_0_0_,changes0_.diff      AS diff2_1_0_,changes0_.path      AS path3_1_0_
FROM   commit_change changes0_
WHERE  changes0_.commit_id = 1 --JdbcTransaction - committed JDBC Connection--Load Commit from cacheSELECT changes0_.commit_id AS commit_i1_0_0_,changes0_.diff      AS diff2_1_0_,changes0_.path      AS path3_1_0_
FROM   commit_change changes0_
WHERE  changes0_.commit_id = 1 --JdbcTransaction - committed JDBC Connection

尽管Commit实体是从缓存中检索的,但Change集合始终是从数据库中获取的。 由于更改也是不可变的,因此我们也希望对其进行缓存,以节省不必要的数据库往返次数。

启用集合缓存支持

默认情况下,不缓存集合,并且要启用此行为,我们必须使用缓存并发策略为它们添加注释:

@ElementCollection
@CollectionTable(name="commit_change",joinColumns=@JoinColumn(name="commit_id")
)
@org.hibernate.annotations.Cache(usage = CacheConcurrencyStrategy.READ_ONLY
)
private List<Change> changes = new ArrayList<>();

重新运行先前的测试将产生以下输出:

--Collections require separate cachingSELECT readonlyca0_.id   AS id1_2_0_,readonlyca0_.NAME AS name2_2_0_
FROM   repository readonlyca0_
WHERE  readonlyca0_.id = 1;INSERT INTO commit(id, repository_id)
VALUES      (DEFAULT, 1);INSERT INTO commit_change(commit_id, diff, path)
VALUES      (1, '0a1,5...', 'README.txt');		 INSERT INTO commit_change(commit_id, diff, path)
VALUES      (1, '17c17...', 'web.xml');--JdbcTransaction - committed JDBC Connection--Load Commit from databaseSELECT readonlyca0_.id   AS id1_2_0_,readonlyca0_.NAME AS name2_2_0_
FROM   repository readonlyca0_
WHERE  readonlyca0_.id = 1;SELECT changes0_.commit_id AS commit_i1_0_0_,changes0_.diff      AS diff2_1_0_,changes0_.path      AS path3_1_0_
FROM   commit_change changes0_
WHERE  changes0_.commit_id = 1 --JdbcTransaction - committed JDBC Connection--Load Commit from cache--JdbcTransaction - committed JDBC Connection

一旦集合被缓存,我们就可以获取Commit实体及其所有Change,而无需访问数据库。

结论

只读实体可以安全地进行缓存,我们可以仅使用第二级缓存来加载整个不可变实体图。 由于高速缓存是直通的 ,因此从数据库中获取实体时将对其进行高速缓存。 只读缓存不是直写的,因为持久存储实体只会在新的数据库行中实现,而不会传播到缓存中。

  • 代码可在GitHub上获得 。

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

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

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

相关文章

漫谈:Java和Python现在都挺火,我应该怎么选?Java和Python优缺点比较。

http://www.bossqiang.com/article/4 声明&#xff1a;这是一篇容易引起撕逼的文章&#xff0c;为了祖国和谐&#xff0c;人民安康&#xff0c;请各位看官尽量理性讨论。同时&#xff0c;这篇文章是面向一些初入行的朋友进行一些相对中肯一点的分析和建议而已&#xff0c;虽然…

Spring集成和Web服务

本文是我们名为“ Spring Integration for EAI ”的学院课程的一部分。 在本课程中&#xff0c;向您介绍了企业应用程序集成模式以及Spring Integration如何解决它们。 接下来&#xff0c;您将深入研究Spring Integration的基础知识&#xff0c;例如通道&#xff0c;转换器和适…

如何在微博首页放置一个二维码?

首先用photoshop打开作为微博背景的图片,还有二维码图片。 然后将二维码图片整合到背景图片的适当位置,并编写相关说明,如下图。 然后将图片保存到桌面。 打开微博,可以看到左侧现在是没有二维码的

RethinkDB创始人教你如何打造一个伟大的互联网产品

关于作者 我叫Slava Akhmechet&#xff0c;本人是 RethinkDB 的创始人之一&#xff0c;RethinkDB是开源&#xff0c;分布式数据库&#xff0c;旨在帮助开发人员与运营商在打造实时应用时处理无结构数据 如何打造一个伟大的互联网产品 假如你认可“销售定乾坤”的原则&#xff0…

Android获取LAUNCHER,Android 获取Launcher 启动列表

先留着有时间再看获取Launcher 启动列表即 列出所有Launcher程序 通过PackageManager 来获取[代码 步骤]1. 定义内部类 LauncherItem 用于定义Application相关属性 比如&#xff1a;图标 名称 以及 ComponentNameJava代码1  public class LauncherItem {23   Drawable icon;…

数据库高可用架构 转载

数据库高可用架构对于我们这些应用端开发的人来说是一个比较陌生的领域&#xff0c;是在具体的数据库产品之上搭建的环境&#xff0c;需要像DBA这样对数据库产品有足够的了解才能有所涉及&#xff0c;虽然不能深入其中&#xff0c;但可以通过一些经典的高可用架构学习其中的思想…

解决 There are no resources that can be added or removed from the server

网上下载了一个项目,在eclipse中部署时,加载项目到tomcat中项目名称无法显示,报出There are no resources that can be added or removed from the server 这个是因为下载下来的项目没有eclipse的相关配置文件,eclipse不知道这是一个什么项目。 解决方法: 1、进入confi…

推荐几款爬虫软件与无需编程的数据分析工具

爬虫软件: 八爪鱼,火车头,前嗅,熊猫采集器,集搜客等 相对来说八爪鱼配置还是比较简单的,不过免费版的爬起数据来那叫一个慢。。。 不过也可能是我是个急性子。。。1分钟爬10条,很心塞啊。火车头就尴尬,不是高 配版。。基本上啥也干不了,不过好的一点是他们的论坛还是…

登录时本地保存账号密码及关闭ARC的方法

对于登录时保存用户名和密码&#xff0c;苹果官方使用的是KeychainItemWrapper&#xff0c;但使用时有些不便&#xff0c;如在引入KeychainItemWrapper的类中都要关闭arc&#xff0c;不能自定义key&#xff0c;必须使用该类提供的kSecValueData、kSecAttrAccount等。所以推荐使…

收银扫描设备统计

前端时间开发一个会员管理系统&#xff0c;里面涉及一些支付的问题&#xff0c;就查找一些配套的硬件设备。记录点滴成长 2000元的配套设备一般就可以满足系统应用啦。

推断:Facebook的新Java静态分析工具

如何使用Facebook的Infer改善Java开发工作流程&#xff1f; 如果您与技术话题保持紧密联系&#xff08;如果您正在阅读此博客&#xff0c;我想您应该这样做&#xff09;&#xff0c;那么您可能听说过Facebook 刚刚向公众发布的新工具&#xff1a;推断。 由于它来自Facebook&am…

html 转换xslt,XSLT xsl:template 元素

元素元素用于构建模板。match 属性用于关联 XML 元素和模板。match 属性也可用来为整个文档定义模板。match 属性的值是 XPath 表达式(举例&#xff0c;match"/" 定义整个文档)。好了&#xff0c;让我们看一下上一节中的 XSL 文件的简化版本&#xff1a;xmlns:xsl&qu…

开发一个大数据网站做的铺垫

知名大数据分析网站推荐8个 用到的大数据5个关键技术 人工智能6大关键技术

如何优化Hibernate EllementCollection语句

介绍 Hibernate支持三种数据映射类型 &#xff1a; 基本 &#xff08;例如String&#xff0c;int&#xff09;&#xff0c; Embeddable和Entity 。 通常&#xff0c;数据库行映射到Entity &#xff0c;每个数据库列都与一个基本属性关联。 当将多个字段映射组合到一个可重用的组…

使用Eclipse将包含第三方jar库的java工程打包成jar包

1、MANIFEST.MF 在工程下新建一个MANIFEST.MF的文件,项目结构如下。 M.java package cn.hwd.main;import java.io.IOException;import org.apache.solr.client.solrj.SolrQuery; import org.apache.solr.client.solrj.SolrServerException; import org.apache.solr.client.s…

史上最牛逼的导航网站(很全很详细)

今天,给大家推荐47个聚合型的导航网站 每一个都收录上百个网站,1个能顶100个,丝毫没有夸张的成分。 (推荐收藏) 设计师导航网站 01 优设导航 https://hao.uisdc.com/ 设计师必备的导航网站,包含设计工具、素材资源、字体设计、配色方案、酷站模板等。 界面清晰无广告…

codeforces 337D Book of Evil(dp)

转载请注明出处&#xff1a; http://www.cnblogs.com/fraud/ ——by fraud Book of Evil Paladin Manao caught the trail of the ancient Book of Evil in a swampy area. This area contains n settlements numbered from 1 to n. Moving through the swamp is ver…

html 如何去滚动条,css怎么去除滚动条?

css可以通过overflow与scroll属性来实现去除滚动条效果。css设置overflow属性为hidden可以实现去除滚动条或设置scroll属性为no。1、这个可以用CSS实现 你可以用JS操作CSS方法一&#xff1a;设置CSS属性overflow为hidden。&#xff1c;body style"overflow:hidden"&a…

阿里云ECS服务器连接不上3306端口?

连不上3306端口一般有三种情况。 1 .本机上防火墙没有开放3306端口,需要自己配置入站规则,或者关闭本机防火墙。 2 .linux 服务器上的 iptables 防火墙没有开放3306端口, 或者关闭服务器上的防火墙。 打开 /etc/sysconfig/iptables 在 "-A INPUT –m state --sta…

UGUI 锚点

今天我们来学习下UGUI的锚点, 他是做什么的呢&#xff1f; 基本上就是用于界面布局. 1. 1个控件对应1个描点. 2. 描点分成四个小叶片, 每1个叶片 对应 控件四边框的角点 3. 不管屏幕如何放大缩小, 控件四边点与 每一个叶片对应的四边点距离不变.(换句话说,按钮的中心与描点的…