最近在项目在使用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 缓存机制学习(一) 树节点搜索问题引发的思考的更多相关文章

  1. JPA,EclipseLink 缓存机制学习——树节点搜索问题引发的思考

    最近在项目在使用JPA+EclipseLink 的方式进行开发,其中EclipseLink使用版本为2.5.1.遇到一些缓存方面使用不当造成的问题,从本篇开始逐步学习EclipseLink的缓存机制. ...

  2. Linux 系统缓存机制学习

    前言:本文为参考他人的文章,是一篇学习记录型博客.理解linux的系统缓存机制有助于理解elasticsearch实时更新的原理. 一.缓存机制 为了提高文件系统性能,内核利用一部分物理内存分配出缓冲 ...

  3. H5缓存机制学习记录

    参考文章:http://mp.weixin.qq.com/s?__biz=MTEwNTM0ODI0MQ==&mid=404724239&idx=1&sn=e0a2887f9ff ...

  4. RecyclerView 缓存机制学习笔记2

    RecyclerView 初始化所有的视图后,调用 去缓存(StaggeredGridLayoutManager), 而不是初始化一次缓存一次 存储后系统又会去调用tryGetViewHolderFo ...

  5. RecyclerView 缓存机制学习笔记1

    盗用别人图片 获取VIew的方法的流程 最先调用 其次调用 这个方法调用会先去缓存 这个是是否有动画,有动画就去里面取. 如果取不到就接着调用 如果在没有继续调用 都取不到就去实例化 调用的次数取决于 ...

  6. MongoDB一次节点宕机引发的思考(源码剖析)

    目录 简介 日志分析 副本集 如何实现 Failover 心跳的实现 electionTimeout 定时器 业务影响评估 参考链接 声明:本文同步发表于 MongoDB 中文社区,传送门: http ...

  7. MongoDB一次节点宕机引发的思考(源码剖析)【华为云分享】

    目录 简介 日志分析 副本集 如何实现 Failover 心跳的实现 electionTimeout 定时器 业务影响评估 参考链接 声明:本文同步发表于 MongoDB 中文社区,传送门:http: ...

  8. CDN缓存机制

    CDN也叫内容分发网络,是一个经策略性部署的整体系统,包括分布式储存.负载均衡.网络请求的重定向和内容管理4个要件.而其中内容管理和全局的网络流量管理是CDN的核心所在.通过用户就进行和服务器负载的判 ...

  9. C#无限极分类树-创建-排序-读取 用Asp.Net Core+EF实现之方法二:加入缓存机制

    在上一篇文章中我用递归方法实现了管理菜单,在上一节我也提到要考虑用缓存,也算是学习一下.Net Core的缓存机制. 关于.Net Core的缓存,官方有三种实现: 1.In Memory Cachi ...

随机推荐

  1. android switch语句报错:case expressions must be constant expressions

    今天无意中碰见了   case expressions must be constant expressions 的问题 写了一个 switch(item.getItemId()) { case R. ...

  2. css实现三角效果

    demo     <!DOCTYPE html> <html lang="zh"> <head> <meta charset=utf-8& ...

  3. 个人训练记录-赛码"bestcoder"杯中国大学生程序设计冠军赛

    A.Movie 题意是给n个线段,要求求出是否存在三个不相交的线段,是的话输出yes,否则输出no.根据贪心的想法,可以先找出右端点r'最小的线段,他是三条线段中最左的那条,再找出左端点l'最大的线段 ...

  4. shell: bad interpreter: No such file or directory

    执行shell脚本    错误提示如下:    bash: ./back : bad interpreter:No such file or directory 因为操作系统是windows,在win ...

  5. CCNET+MSBuild+SVN实现每日构建

    最近开始将源代码迁移到SVN,于是便考虑到如何从SVN定期获取源码,自动编译并部署以减轻工作量并提高工作效率.通过多方搜集资料并进行研究,基本实现了这个功能.对于每日构建的概念就不具体展开了,可以在各 ...

  6. Qt编译安装qwt错误moc/xxx Error:126

    最近搞设计,需要在上位机上绘制曲线,在网上找了找,发现python的matplotlib和Qt的qwt都不错,本着难度最小原则,选择了Qt下面的qwt,安装过程中遇到了编译错误:moc/xxx Err ...

  7. Ansible 学习笔记

    最近因为需要管理很多台机器,而这些机器又需要频繁重新安装,实在受不了Puppet需要在每个客户机上都安装一遍,于是转头开始学些Ansible.根据这段时间的使用,这个确实是神器,唯一的感觉就是相见恨晚 ...

  8. 响应式内容滑动插件jQuery.bxSlider

    bxSlider特性 1.充分响应各种设备,适应各种屏幕: 2.支持多种滑动模式,水平.垂直以及淡入淡出效果: 3.支持图片.视频以及任意html内容: 4.支持触摸滑动: 5.支持Firefox,C ...

  9. 【数论】X problem

    X problem      X问题     Time Limit: 1000/1000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Othe ...

  10. listview和checkbox的冲突的用法

    package com.exaple.music; import java.util.List; import java.util.Timer; import java.util.TimerTask; ...