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
<?xml version="1.0" encoding="UTF-8"?>
<!-- <ehcache> -->
<ehcache xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:noNamespaceSchemaLocation="ehcache.xsd"> <!--
磁盘存储:将缓存中暂时不使用的对象,转移到硬盘,类似于Windows系统的虚拟内存
path:指定在硬盘上存储对象的路径
path可以配置的目录有:
user.home(用户的家目录)
user.dir(用户当前的工作目录)
java.io.tmpdir(默认的临时目录)
ehcache.disk.store.dir(ehcache的配置目录)
绝对路径(如:d:\\ehcache)
查看路径方法:String tmpDir = System.getProperty("java.io.tmpdir");
-->
<diskStore path="java.io.tmpdir" /> <!-- 配置提供者 1、peerDiscovery,提供者方式,有两种方式:自动发现(automatic)、手动配置(manual) 2、rmiUrls,手动方式时提供者的地址,多个的话用|隔开 -->
<!-- <cacheManagerPeerProviderFactory
class="net.sf.ehcache.distribution.RMICacheManagerPeerProviderFactory"
properties="peerDiscovery=manual,rmiUrls=//127.0.0.1:40002/userCache" /> -->
<cacheManagerPeerProviderFactory
class="net.sf.ehcache.distribution.RMICacheManagerPeerProviderFactory"
properties="peerDiscovery=automatic, multicastGroupAddress=230.0.0.1, multicastGroupPort=4446,timeToLive=255"/>
<!-- <cacheManagerPeerProviderFactory
class="org.ehcache.distribution.RMICacheManagerPeerProviderFactory"
properties="peerDiscovery=automatic, multicastGroupAddress=230.0.0.1, multicastGroupPort=4446,timeToLive=255"/> --> <!-- 配置监听器 1、hostName 主机地址 2、port 端口 3、socketTimeoutMillis socket子模块的超时时间,默认是2000ms -->
<!-- <cacheManagerPeerListenerFactory
class="net.sf.ehcache.distribution.RMICacheManagerPeerListenerFactory"
properties="hostName=127.0.0.1, port=40001, socketTimeoutMillis=2000" /> -->
<cacheManagerPeerListenerFactory
class="net.sf.ehcache.distribution.RMICacheManagerPeerListenerFactory"/> <!--
defaultCache:默认的缓存配置信息,如果不加特殊说明,则所有对象按照此配置项处理
maxElementsInMemory:设置了缓存的上限,最多存储多少个记录对象
eternal:代表对象是否永不过期 (指定true则下面两项配置需为0无限期)
timeToIdleSeconds:最大的闲置时间 /秒
timeToLiveSeconds:最大的存活时间 /秒
overflowToDisk:是否允许对象被写入到磁盘
说明:下列配置自缓存建立起600秒(10分钟)有效 。
在有效的600秒(10分钟)内,如果连续120秒(2分钟)未访问缓存,则缓存失效。
就算有访问,也只会存活600秒。
-->
<defaultCache maxElementsInMemory="10000" eternal="false"
timeToIdleSeconds="600" timeToLiveSeconds="600" overflowToDisk="true" /> <cache name="*.*.*.*.dao.WarnMapper" maxElementsInMemory="10000" eternal="false"
timeToIdleSeconds="120" timeToLiveSeconds="300" overflowToDisk="true" /> <cache name="*.*.*.*.dao.ProjectMapper" maxElementsInMemory="10000" eternal="false"
timeToIdleSeconds="120" timeToLiveSeconds="300" overflowToDisk="true" />
</ehcache>
配置 application.properties
# Ehcache缓存
spring.cache.type=ehcache
spring.cache.ehcache.config=classpath:/ehcache.xml
业务逻辑层代码
package *.*.*.common.utils; import net.sf.ehcache.Cache;
import net.sf.ehcache.CacheManager; public class EhcacheUtil { // 构建一个缓存管理器
private static CacheManager cacheManager = CacheManager.newInstance("src/main/resources/ehcache.xml"); /**
* action 清除相关联的缓存
* @param cacheName 缓存所在namespace的名称
* @param keys 缓存所在namespace下key的名称,为空则默认清空所有key
* @return
*/
public static void clearRelatedCache( String cacheName, String[] keys ) {
Cache cache = cacheManager.getCache(cacheName) ;
if ( cache==null ) {
return ;
}
//若缓存不为空
if ( keys==null || keys.length==0 ) {
cache.removeAll();
}
else {
for (String key : keys) {
cache.remove(key) ;
}
}
} }
1 @PostMapping("/delete")
public Result delete(HttpServletRequest request) {
Long projectId = StringUtil.getLong(request.getParameter("id")) ;
Project project = projectService.findById(projectId) ;
if(project==null) {
return ResultGenerator.genFailResult(ResultCode.UNAUTHORIZED, "工程id不正确");
}
projectService.deleteById(projectId);;
EhcacheUtil.clearRelatedCache(CacheConstants.CACHE_NAMESPACE_WARNMAPPER, null) ;
return ResultGenerator.genSuccessResult("删除成功");
}
共同学习,共同进步,若有补充,欢迎指出,谢谢!
Springboot + Mybatis + Ehcache的更多相关文章
- Shiro+springboot+mybatis+EhCache(md5+salt+散列)认证与授权-03
从上文:Shiro+springboot+mybatis(md5+salt+散列)认证与授权-02 当每次进行刷新时,都会从数据库重新查询数据进行授权操作,这样无疑给数据库造成很大的压力,所以需要引入 ...
- springboot+mybatis+ehcache实现缓存数据
一.springboot缓存简介 在 Spring Boot中,通过@EnableCaching注解自动化配置合适的缓存管理器(CacheManager),Spring Boot根据下面的顺序去侦测缓 ...
- springboot+mybatis+redis实现分布式缓存
大家都知道springboot项目都是微服务部署,A服务和B服务分开部署,那么它们如何更新或者获取共有模块的缓存数据,或者给A服务做分布式集群负载,如何确保A服务的所有集群都能同步公共模块的缓存数据, ...
- spring boot学习(十三)SpringBoot缓存(EhCache 2.x 篇)
SpringBoot 缓存(EhCache 2.x 篇) SpringBoot 缓存 在 Spring Boot中,通过@EnableCaching注解自动化配置合适的缓存管理器(CacheManag ...
- (转)springMVC+mybatis+ehcache详细配置
一. Mybatis+Ehcache配置 为了提高MyBatis的性能,有时候我们需要加入缓存支持,目前用的比较多的缓存莫过于ehcache缓存了,ehcache性能强大,而且位各种应用都提供了解决方 ...
- 第五章 springboot + mybatis(转载)
本编博客转发自:http://www.cnblogs.com/java-zhao/p/5350021.html springboot集成了springJDBC与JPA,但是没有集成mybatis,所以 ...
- 第九章 springboot + mybatis + 多数据源 (AOP实现)
在第八章 springboot + mybatis + 多数据源代码的基础上,做两点修改 1.ShopDao package com.xxx.firstboot.dao; import org.spr ...
- 第五章 springboot + mybatis
springboot集成了springJDBC与JPA,但是没有集成mybatis,所以想要使用mybatis就要自己去集成.集成方式相当简单. 1.项目结构 2.pom.xml <!-- 与数 ...
- 基于Maven的Springboot+Mybatis+Druid+Swagger2+mybatis-generator框架环境搭建
基于Maven的Springboot+Mybatis+Druid+Swagger2+mybatis-generator框架环境搭建 前言 最近做回后台开发,重新抓起以前学过的SSM(Spring+Sp ...
随机推荐
- ZOJ Problem Set - 1003
1.翻译参考 http://www.cnblogs.com/woodfish1988/archive/2006/11/10/556926.html 2.代码参考 http://www.cnblogs. ...
- [bzoj4842][bzoj1283][Neerc2016]Delight for a Cat/序列_线性规划_费用流
4842: [Neerc2016]Delight for a Cat_1283: 序列 题目大意:ls是一个特别堕落的小朋友,对于n个连续的小时,他将要么睡觉要么打隔膜,一个小时内他不能既睡觉也打隔膜 ...
- Redis(1.3)Redis的基本特性(事务、多数据库)
[1]两大特性 (1)多数据库 1个redis实例 可以有16个数据库,默认下标为0~15,默认连接到的是 0 下标的数据库. (2)事务 [2]多数据库 [2.1]概念 1个redis实例 可以有1 ...
- SQL 查看某个表被哪些存储过程或者视图使用
--查询某个表被哪些视图/存储过程使用(type='P':表示存储过程,type='V':表示视图) SELECT OBJECT_NAME(id) FROM syscomments WHERE id ...
- SQLite进阶-9.别名
我们可以暂时给表或者列重命名为另一个名字,称为别名,重命名只是临时运行时改变,不会改变数据库中的实际的名字. -- 语法 SELECT column_name AS column_alias_name ...
- SetIcon(m_hIcon, TRUE);的作用
SetIcon(m_hIcon, FALSE);// Set small icon 这条语句,程序显示时,左上角就会显示定义了的图标,生成的EXE程序也显示了这个图标 SetIcon(m_hIcon, ...
- 使用AI算法进行手写数字识别
人工智能 人工智能(Artificial Intelligence,简称AI)一词最初是在1956年Dartmouth学会上提出的,从那以后,研究者们发展了众多理论和原理,人工智能的概念也随之扩展 ...
- 18-Perl 错误处理
1.Perl 错误处理程序运行过程中,总会碰到各式各样的错误,比如打开一个不存在的文件.程序运行过程中如果出现错误就会停止,我们就需要使用一些检测方法来避免错误,从而防止程序退出.Perl 提供了多中 ...
- MVC4学习要点记一
强类型的辅助方法:这些helper的特征是名称后面加上了 For , 这些叫做强类型的辅助方法. 共用布局页:可以在Views文件夹下面新建一个视图页,命名为_ViewStart.cshtml,将这部 ...
- Java Jersey的详情概述
Jersey是一个RESTFUL请求服务JAVA框架,与常规的JAVA编程使用的struts框架类似,它主要用于处理业务逻辑层. 与springmvc 的区别: 1. jersey同样提供DI,是由g ...