JPA,EclipseLink 缓存机制学习(一) 树节点搜索问题引发的思考
最近在项目在使用JPA+EclipseLink 的方式进行开发,其中EclipseLink使用版本为2.5.1。遇到一些缓存方面使用不当造成的问题,从本篇开始逐步学习EclipseLink的缓存机制。
一、树节点搜索问题出现
故事是这样的:项目中有一个对树节点搜索的需求,如下图中所示,按照前缀匹配查询节点名称中包含OK的节点,将返回下图中的数据结构。基本实现就是:1.先查找出OK节点,然后根据该节点的父节点id获得父节点,也就是PERSON2结点,同样按照PERSON2的父结点id找到节点ROOT。结点的类图大概是这样子的,每获得父节点后,会将本身节点加入到父结点children集合中去。
(图a)
一开始按照特定顺序在操作中出现奇怪的现象。
step 1. 检索包含OK的结点 显示正常,如图b所示。
step 2. 检索包含PERSON名称的节点,结果如图c所示。
step 3. 又一次检索OK的节点,结果奇怪的结果出现了,见图d。理想中的结果数据是不包含PERSON1的,这显然是一个缓存导致的问题。
(图b)
(图c)
(图d)
二、EclipseLink 缓存架构

其中几个基本概念:
1. Session Cache,即 Persistence Unit Cache,属于系统级的缓存,所有client共享数据。数据来源主要有两种:
a)通过EntityManager进行数据读入时,会将读入的数据拷贝一份放到Session Cache;
b) Unit of Work Cache 进行Commit操作成功后,将数据同步到Session Cache中;
2. Unit of Work Cache,即Persistence Context Cache,属于隔离型缓存,属于单个client。由EntityManager进行管理,Persistence Context中保存着读取过的Entity实例。当对Entity执行了Commit操作后会将更改后对数据同步到Session Cache。Flush,Clear操作不会触发同步Session Cache操作。
3. 数据查询过程。EntityManager根据实例唯一标识查看Persistence Context Cache中是否存在该实例,如果存在则返回该实例。如果不存在,则查询Persistence Unit Cache中是否存在该实例,如果存在则直接返回该实例,如果不存在则访问数据库进行查询,得到数据结果后将此数据保存到Persistence Unit Cache 和 Persistence Context Cache中。
三、Entity缓存隔离类型(决定是否将查询数据存入到共享缓存中)
1.SHARED
共享缓存,也是系统默认的配置。EnittyManger在进行查询操作的时后,返回的数据会在Session Cache/EntityManagerFactory中保存一部分。
2.PROTECTED
被保护的。EnittyManger在进行查询操作的时后,返回的数据并不会在Session Cache中保存完整的Entity实例,只会保存Entity状态信息。
3.ISOLATED
隔离的。EnittyManger在进行查询操作的时后,返回的数据不会在Session Cache/EntityManagerFactory中保存,只保存在Persistence Context Cache中。
四、Entity缓存类型(决定缓存有效时间)
1.FULL
将缓存该Entity的所有查询到的实例,随时可以通过唯一标识通过缓存进行获取。由于该缓存数据不会被gc清除,所以要当心,对于数量庞大的Entity实例对象有可能导致Out Of Memory。
2.WEAK
将该缓存的所有Entity实例以Weak Reference的引用方式进行缓存。当gc执行的时候,缓存将被清除。
3.SOFT
将该缓存的所有Entity实例以Soft Reference的引用方式进行缓存。当JVM可用内存过低时将对这部分缓存进行释放。
4.SOFT_WEAK
此为系统默认配置。将该缓存的所有Entity实例以Soft Reference 与 Weak Reference 相结合的方式进行缓存。此缓存类型和WEAK类型的区别在于,存在一个基于Soft Reference的most-frequently-used的子缓存,读取最频繁的Entity实例将保存在这里,避免gc回收读取频繁的Entity实例。该子缓冲区大小可以通过设置@Cache中的size属性来调节。
5.HARD_WEAK
此缓存类型和SOFT_WEAK很相似,区别在于子缓存区用Hard Reference 进行存储,保证即使JVM内存过低,也不会清除这部分缓存数据。
6.CACHE
缓存唯一标识map维护一个指定大小的缓存,对象被移出缓存策略按照LRU ( Least Recently Used)。
7.NONE
对该Entity不进行任何缓存。
五、搜索问题出现的原因
使用了Spring-data-JPA,持久化层通过继承接口org.springframework.data.jpa.repository.JpaRepository实现。根据debug结果发现实现类为org.springframework.data.jpa.repository.support.SimpleJpaRepository。其中每个SimpleJpaRepository实例有一个EntityManager,且在该Repository实例化后服务期间EntityManager类型的成员变量没有变化(HashCode相同)。可以认为使用的是同一个Persistence Context Cache。根据前文对缓存的分析,Node类型缓存隔离类型为SHARED,缓存类型为SOFT_WEAK,每次根据id对Node的查询都要先从Persistence Context Cache中找,结果step 2中对ROOT节点设置完Children,step 3中直接又从Persistence Context Cache中得到了该ROOT对象,导致无效数据(step 3)的出现。
六、解决方案
我第一想到的就是不要让Node类型被缓存起来,即在Entity类型中增加@Cache(type=CacheType.NONE)。问题虽然按照这种方式解决了,但是带来效率的下降。比如Node节点有获取整棵树数据的方法。具体优化方案将在后续JPA后续文章中给出。
七、参考
EclipseLink Cache
https://www.eclipse.org/eclipselink/documentation/2.5/concepts/cache001.htm
EclipseLink 源码地址:
https://www.eclipse.org/eclipselink/downloads/previous_releases.php
八、结语
欢迎大家吐槽、拍砖、指正 ^_^
JPA,EclipseLink 缓存机制学习(一) 树节点搜索问题引发的思考的更多相关文章
- JPA,EclipseLink 缓存机制学习——树节点搜索问题引发的思考
最近在项目在使用JPA+EclipseLink 的方式进行开发,其中EclipseLink使用版本为2.5.1.遇到一些缓存方面使用不当造成的问题,从本篇开始逐步学习EclipseLink的缓存机制. ...
- Linux 系统缓存机制学习
前言:本文为参考他人的文章,是一篇学习记录型博客.理解linux的系统缓存机制有助于理解elasticsearch实时更新的原理. 一.缓存机制 为了提高文件系统性能,内核利用一部分物理内存分配出缓冲 ...
- H5缓存机制学习记录
参考文章:http://mp.weixin.qq.com/s?__biz=MTEwNTM0ODI0MQ==&mid=404724239&idx=1&sn=e0a2887f9ff ...
- RecyclerView 缓存机制学习笔记2
RecyclerView 初始化所有的视图后,调用 去缓存(StaggeredGridLayoutManager), 而不是初始化一次缓存一次 存储后系统又会去调用tryGetViewHolderFo ...
- RecyclerView 缓存机制学习笔记1
盗用别人图片 获取VIew的方法的流程 最先调用 其次调用 这个方法调用会先去缓存 这个是是否有动画,有动画就去里面取. 如果取不到就接着调用 如果在没有继续调用 都取不到就去实例化 调用的次数取决于 ...
- MongoDB一次节点宕机引发的思考(源码剖析)
目录 简介 日志分析 副本集 如何实现 Failover 心跳的实现 electionTimeout 定时器 业务影响评估 参考链接 声明:本文同步发表于 MongoDB 中文社区,传送门: http ...
- MongoDB一次节点宕机引发的思考(源码剖析)【华为云分享】
目录 简介 日志分析 副本集 如何实现 Failover 心跳的实现 electionTimeout 定时器 业务影响评估 参考链接 声明:本文同步发表于 MongoDB 中文社区,传送门:http: ...
- CDN缓存机制
CDN也叫内容分发网络,是一个经策略性部署的整体系统,包括分布式储存.负载均衡.网络请求的重定向和内容管理4个要件.而其中内容管理和全局的网络流量管理是CDN的核心所在.通过用户就进行和服务器负载的判 ...
- C#无限极分类树-创建-排序-读取 用Asp.Net Core+EF实现之方法二:加入缓存机制
在上一篇文章中我用递归方法实现了管理菜单,在上一节我也提到要考虑用缓存,也算是学习一下.Net Core的缓存机制. 关于.Net Core的缓存,官方有三种实现: 1.In Memory Cachi ...
随机推荐
- paper 132:图像去噪算法:NL-Means和BM3D
这篇文章写的非常好,确定要~认真~慎重~的转载了,具体请关注本文编辑作者:http://wenhuix.github.io/research/denoise.html 我不会告诉你这里的代码都是f ...
- spring-cloud-event-sourcing-example-master 运行效果及说明
1.微服务架构下电商示例,部署成功!监控等技术细节未深入研究. 简单介绍: 配置服务(config-service ),端口8888,健康检查 xx:8888/hea ...
- Android 中如何计算 App 的启动时间?
(转载) 已知的两种方法貌似可以获取,但是感觉结果不准确:一种是,adb shell am start -w packagename/activity,这个可以得到两个值,ThisTime和Total ...
- 无光驱在32位windows系统下安装64位windows系统
位的系统. 大家都知道,32位的操作系统最多只能支持3.2G的内存,现在内存白菜价,很多人都在原有基础上购入新内存,这样最少也有4G了,为了让内存不浪费,我 们只有升级到64位操作系统.但是很多朋友又 ...
- css3动画之小牛奔跑
今天突然看到阿里云官网的一个悬浮效果挺炫的,就想知道到底是怎么做的,研究了半天,加了一个技术群,原来是css3做的,然后做了一个小 Demo记录下来: <!DOCTYPE html> &l ...
- 数据流 in redux
之前用学过的react和react-router写了个单页面应用,但写完后总感觉还欠缺点什么,怎么说呢,就是感觉在数据流的控制上被框架约束的厉害,很不自由,比如兄弟组件间的通信就很不方便.然后才了解到 ...
- Spring学习笔记之四----基于Annotation的Spring AOP编程
你能使用@Aspect annotation将某个Java类标注为Aspect,这个Aspect类里的所有公有方法都可以成为一个Advice,Spring提供了5个Annotation去将某个方法标注 ...
- asp.net 事件加载顺序
下面是母版页与内容页合并后事件的发生顺序: 母版页控件 Init 事件. 内容控件 Init 事件. 母版页 Init 事件. 内容页 Init 事件. 内容页 Load 事件. 母版页 Load 事 ...
- C#的HTTP协议中POST与GET的区别
引言 HTTP协议我想任何IT人士都耳熟能详了,大家都能说出个所以然来.但是如果我问你HTTP协议的请求方法有哪些?POST与GET的差异?GET或POST传送数据量的大小有限制吗?HTTP响应的状态 ...
- 测试 Prism 语法高亮
测试 Prism 对 C 语言的语法高亮 #include <stdio.h> #include "math.h" int main(void) { long int ...