• Springboot + Mybatis + Ehcache


    最近在做一个项目,为处理并发性较差的问题,使用了Mybatis二级缓存

    但在多表联合查询的情况下,Mybatis二级缓存是存在着数据脏读的问题的

    两天就是在想办法解决这个数据脏读的问题

    考虑到简易性、性能、兼容性、可扩展性,我选择了springboot自带的 Ehcache 框架来整合解决这个问题

    我也是第一次接触到 Ehcache 这个框架,所以也算从零开始

    根据Mybatis二级缓存的特点,我的思路是

      每当 增删改 某张表 , 就清除刷新其关联的所有表的 缓存

    ( 这里可分为两个大小方向:

    在 增删改 的方法上,做相关的 关联清除缓存 操作  ——  这个就比较细节化一点,做的修改可能会比较多

    在 增删改方法 所在类的整体上,做相关的 关联清除缓存操作  —— 这个我需要做的修改就相对少点,但这样里面每个方法(包括一些无关紧要的)都会触发这个清除缓存操作

    都各有利弊 )

    一路上并不顺利,

    一开始我尝试自己看能不能找到比较好的方法,但刚接触一下子就自己解决也是不太可能的

    但有看到一个解决Mybatis二级缓存问题的插件 —— GitHub上 LuanLouis 的 mybatis-enhanced-cache 

    但这个project是5年前写的,而且最近一次更新也只是2年前,现在技术发展那么快,看到的时候就感觉可能不行

    后面自己也下载了下来,mvn install 发现不成功,缺少ojdbc14的jar包 ,网上说ojdbc14.jar 是收费的,所以中央库是导不了这个包

    看了一些资料说,Oracle安装目录里面有,但公司这台没装Oracle ;也有资料说,可以用 ojdbc6 或其他ojdbc代替,我就下载了ojdbc6 和ojdbc8 都试了一下,都能够解决那个ojdbc jar包的问题,

    mybatis-enhanced-cache 插件的jar也成功导入了maven库和项目中,但导入之后,用的时候却又发现报各种错,就觉得凉了,

    本来就是为了简单快速,才想用别人的插件,所以我不可能自己又去修改这个插件来用,改了又不一定能用!所以使用插件这个方案就只能放弃了

    后来,又找了网上很多资料,也按很多示例的步骤做了

    像各种注解、各种配置什么的,都不知道是和mybatis的注解冲突了,还是我写的无效

    (像网上很多资料说的,mybatis二级缓存是不推荐使用的,至于为什么我还要用,可以看我前面一篇文章——  缓存的设计与使用  ,

    所以在方面遇到我这样问题的应该没几个,也就找不到多少资料,只能靠自己)

    想了很多可能性,试了一次又一次,想尽量做得简单点,直接简单XML配置加注解 ,能够这样就好了。

    但现实是残酷的,做了不知多少次的尝试,还是没成功,无计可施,最后还是只能放弃这个方案了

    没有办法,就只能选择最后一种方案了 —— 自己写代码,在业务逻辑层 做处理

    这对一无所知的菜鸟,也不容易啊

    好在坚持尝试,最后终于找到解决方案

    配置 ehcache.xml

     1 <?xml version="1.0" encoding="UTF-8"?>
     2 <!-- <ehcache> -->
     3 <ehcache xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
     4          xsi:noNamespaceSchemaLocation="ehcache.xsd">
     5 
     6     <!--
     7         磁盘存储:将缓存中暂时不使用的对象,转移到硬盘,类似于Windows系统的虚拟内存
     8         path:指定在硬盘上存储对象的路径
     9         path可以配置的目录有:
    10             user.home(用户的家目录)
    11             user.dir(用户当前的工作目录)
    12             java.io.tmpdir(默认的临时目录)
    13             ehcache.disk.store.dir(ehcache的配置目录)
    14             绝对路径(如:d:\ehcache)
    15         查看路径方法:String tmpDir = System.getProperty("java.io.tmpdir");
    16      -->
    17     <diskStore path="java.io.tmpdir" />
    18 
    19     <!-- 配置提供者 1、peerDiscovery,提供者方式,有两种方式:自动发现(automatic)、手动配置(manual) 2、rmiUrls,手动方式时提供者的地址,多个的话用|隔开 -->
    20     <!-- <cacheManagerPeerProviderFactory
    21         class="net.sf.ehcache.distribution.RMICacheManagerPeerProviderFactory"
    22         properties="peerDiscovery=manual,rmiUrls=//127.0.0.1:40002/userCache" /> -->
    23     <cacheManagerPeerProviderFactory
    24         class="net.sf.ehcache.distribution.RMICacheManagerPeerProviderFactory"
    25         properties="peerDiscovery=automatic, multicastGroupAddress=230.0.0.1, multicastGroupPort=4446,timeToLive=255"/>
    26     <!-- <cacheManagerPeerProviderFactory
    27         class="org.ehcache.distribution.RMICacheManagerPeerProviderFactory"
    28         properties="peerDiscovery=automatic, multicastGroupAddress=230.0.0.1, multicastGroupPort=4446,timeToLive=255"/> -->
    29 
    30     <!-- 配置监听器 1、hostName 主机地址 2、port 端口 3、socketTimeoutMillis socket子模块的超时时间,默认是2000ms -->
    31     <!-- <cacheManagerPeerListenerFactory
    32         class="net.sf.ehcache.distribution.RMICacheManagerPeerListenerFactory"
    33         properties="hostName=127.0.0.1, port=40001, socketTimeoutMillis=2000" /> -->
    34     <cacheManagerPeerListenerFactory
    35          class="net.sf.ehcache.distribution.RMICacheManagerPeerListenerFactory"/>
    36 
    37 
    38     <!--
    39         defaultCache:默认的缓存配置信息,如果不加特殊说明,则所有对象按照此配置项处理
    40         maxElementsInMemory:设置了缓存的上限,最多存储多少个记录对象
    41         eternal:代表对象是否永不过期 (指定true则下面两项配置需为0无限期)
    42         timeToIdleSeconds:最大的闲置时间 /秒
    43         timeToLiveSeconds:最大的存活时间 /秒
    44         overflowToDisk:是否允许对象被写入到磁盘
    45         说明:下列配置自缓存建立起600秒(10分钟)有效 。
    46         在有效的600秒(10分钟)内,如果连续120秒(2分钟)未访问缓存,则缓存失效。
    47         就算有访问,也只会存活600秒。
    48      -->
    49     <defaultCache maxElementsInMemory="10000" eternal="false"
    50                   timeToIdleSeconds="600" timeToLiveSeconds="600" overflowToDisk="true" />
    51 
    52     <cache name="*.*.*.*.dao.WarnMapper" maxElementsInMemory="10000" eternal="false"
    53                   timeToIdleSeconds="120" timeToLiveSeconds="300" overflowToDisk="true" />
    54 
    55     <cache name="*.*.*.*.dao.ProjectMapper" maxElementsInMemory="10000" eternal="false" 
    56           timeToIdleSeconds="120" timeToLiveSeconds="300" overflowToDisk="true" />
    57 </ehcache>

    配置 application.properties 

    1 # Ehcache缓存
    2 spring.cache.type=ehcache
    3 spring.cache.ehcache.config=classpath:/ehcache.xml

    业务逻辑层代码

     1 package *.*.*.common.utils;
     2 
     3 import net.sf.ehcache.Cache;
     4 import net.sf.ehcache.CacheManager;
     5 
     6 public class EhcacheUtil {
     7 
     8     // 构建一个缓存管理器
     9     private static CacheManager cacheManager = CacheManager.newInstance("src/main/resources/ehcache.xml");  
    10     
    11     /**
    12      * action 清除相关联的缓存
    13      * @param cacheName 缓存所在namespace的名称
    14      * @param keys   缓存所在namespace下key的名称,为空则默认清空所有key
    15      * @return 
    16      */
    17     public static void clearRelatedCache( String cacheName, String[] keys ) {
    18         Cache cache = cacheManager.getCache(cacheName) ;    
    19         if ( cache==null ) { 
    20             return ;
    21         }
    22         //若缓存不为空
    23         if ( keys==null || keys.length==0 ) {
    24             cache.removeAll();
    25         }
    26         else {
    27             for (String key : keys) {
    28                 cache.remove(key) ;
    29             }            
    30         }
    31     }
    32 
    33 }
     1    @PostMapping("/delete")
     2     public Result delete(HttpServletRequest request) {
     3         Long projectId = StringUtil.getLong(request.getParameter("id")) ;
     4         Project project = projectService.findById(projectId) ;
     5         if(project==null) {
     6             return ResultGenerator.genFailResult(ResultCode.UNAUTHORIZED, "工程id不正确");
     7         }
     8         projectService.deleteById(projectId);;
     9         EhcacheUtil.clearRelatedCache(CacheConstants.CACHE_NAMESPACE_WARNMAPPER, null) ;
    10         return ResultGenerator.genSuccessResult("删除成功");
    11     }

    共同学习,共同进步,若有补充,欢迎指出,谢谢!

  • 相关阅读:
    bzoj_auto_submiter(辣鸡Py毁我青春系列)
    听说“辣鸡小隔膜”出V1.3了?
    shell脚本:统计分析 /home/ 目录用户磁盘使用情况
    shell脚本:DNS自检脚本
    Linux命令集锦:ssh命令
    Linux用户权限
    Linux文件属性
    Linux命令集锦:chown命令
    Linux命令集锦:chmod命令
    Linux命令集锦:tmux命令
  • 原文地址:https://www.cnblogs.com/dengguangxue/p/11276791.html
Copyright © 2020-2023  润新知