SpringCache使用

2023-11-06

SpringCache使用

1.引入依赖

引入springcache依赖

<dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-boot-start-cache</artifactId>
</dependency>

使用的是redis缓存,也要引入redis缓存

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-data-redis</artifactId>
    <exclusions>
    <exclusion>
    <groupId>io.lettuce</groupId>
    <artifactId>lettuce-core</artifactId>
    </exclusion>
    </exclusions>
</dependency>

为什么去除lettuce,参考《分布式缓存》,引入redisson控制

2.写配置

(1)自动配置用了哪些类?

CacheAutoConfiguration会导入RedisCacheConfiguration然后自动配置
RedisChacheManager

因为源码自动配置了

static class CacheConfigurationImportSelector implements ImportSelector {

		@Override
		public String[] selectImports(AnnotationMetadata importingClassMetadata) {
			CacheType[] types = CacheType.values();
			String[] imports = new String[types.length];
			for (int i = 0; i < types.length; i++) {
				imports[i] = CacheConfigurations.getConfigurationClass(types[i]);
			}
			return imports;
		}
	}

3.测试使用缓存

开启缓存

@EnableCaching //开启缓存
public class GulidemoProductApplication {
    public static void main(String[] args) {
        SpringApplication.run (GulidemoProductApplication.class, args);
    }

}
@Cacheable 触发把一个数据保存到缓存里面
@CacheEvict 触发将缓存删除的操作
@CachePut 不影响方法执行更新缓存
@Caching 组合以上多个操作
@CacheConfig 在类级别上既同一个类上共享缓存的配置

在这里插入图片描述

 //指定缓存的名称,可以用来分区,按业务类型分区
    @Cacheable("ategorys")//代表当前方法需要缓存,如果缓存中有、该方法不会被调用。如果缓存没有,执行完方法后结果会缓存进缓存
    

设置redis自动配置

自动配置源码

CacheAutoConfiguration

// 缓存自动配置源码
@Configuration(proxyBeanMethods = false)
@ConditionalOnClass(CacheManager.class)
@ConditionalOnBean(CacheAspectSupport.class)
@ConditionalOnMissingBean(value = CacheManager.class, name = "cacheResolver")
@EnableConfigurationProperties(CacheProperties.class)
@AutoConfigureAfter({ CouchbaseAutoConfiguration.class, HazelcastAutoConfiguration.class,
                     HibernateJpaAutoConfiguration.class, RedisAutoConfiguration.class })
@Import({ CacheConfigurationImportSelector.class, // 看导入什么CacheConfiguration
         CacheManagerEntityManagerFactoryDependsOnPostProcessor.class })
public class CacheAutoConfiguration {

    @Bean
    @ConditionalOnMissingBean
    public CacheManagerCustomizers cacheManagerCustomizers(ObjectProvider<CacheManagerCustomizer<?>> customizers) {
        return new CacheManagerCustomizers(customizers.orderedStream().collect(Collectors.toList()));
    }

    @Bean
    public CacheManagerValidator cacheAutoConfigurationValidator(CacheProperties cacheProperties,
                                                                 ObjectProvider<CacheManager> cacheManager) {
        return new CacheManagerValidator(cacheProperties, cacheManager);
    }

    @ConditionalOnClass(LocalContainerEntityManagerFactoryBean.class)
    @ConditionalOnBean(AbstractEntityManagerFactoryBean.class)
    static class CacheManagerEntityManagerFactoryDependsOnPostProcessor
        extends EntityManagerFactoryDependsOnPostProcessor {

        CacheManagerEntityManagerFactoryDependsOnPostProcessor() {
            super("cacheManager");
        }

    }

RedisCacheConfiguration

@Configuration(proxyBeanMethods = false)
@ConditionalOnClass(RedisConnectionFactory.class)
@AutoConfigureAfter(RedisAutoConfiguration.class)
@ConditionalOnBean(RedisConnectionFactory.class)
@ConditionalOnMissingBean(CacheManager.class)
@Conditional(CacheCondition.class)
class RedisCacheConfiguration {

    @Bean // 放入缓存管理器
    RedisCacheManager cacheManager(CacheProperties cacheProperties, 
                                   CacheManagerCustomizers cacheManagerCustomizers,
                                   ObjectProvider<org.springframework.data.redis.cache.RedisCacheConfiguration> redisCacheConfiguration,
                                   ObjectProvider<RedisCacheManagerBuilderCustomizer> redisCacheManagerBuilderCustomizers,
                                   RedisConnectionFactory redisConnectionFactory, ResourceLoader resourceLoader) {
        RedisCacheManagerBuilder builder = RedisCacheManager.builder(redisConnectionFactory).cacheDefaults(
            determineConfiguration(cacheProperties, redisCacheConfiguration, resourceLoader.getClassLoader()));
        List<String> cacheNames = cacheProperties.getCacheNames();
        if (!cacheNames.isEmpty()) {
            builder.initialCacheNames(new LinkedHashSet<>(cacheNames));
        }
        redisCacheManagerBuilderCustomizers.orderedStream().forEach((customizer) -> customizer.customize(builder));
        return cacheManagerCustomizers.customize(builder.build());
    }

配置

/**
 * @author qxb
 * @version 0.0.3
 * @description MyCacheConfig
 * @since 2021/6/9 23:28
 */
//EnableConfigurationProperties 将不入spring容器的配置加载入容器
@EnableConfigurationProperties(CacheProperties.class)
@EnableCaching
@Configuration
public class MyCacheConfig {

    //读取EnableConfigurationProperties加载入容器的配置也可以在方法参数上传入使用如 redisCacheConfiguration(CacheProperties cacheProperties)
    @Autowired
    CacheProperties cacheProperties;

    /*设置自定义redis缓存配置入spring容器*/
    @Bean
    RedisCacheConfiguration redisCacheConfiguration(){
        //设置默认配置
        RedisCacheConfiguration config = RedisCacheConfiguration.defaultCacheConfig ();
        config = config.serializeKeysWith (RedisSerializationContext.SerializationPair.fromSerializer (new StringRedisSerializer ()));
        config = config.serializeValuesWith (RedisSerializationContext.SerializationPair.fromSerializer (new GenericJackson2JsonRedisSerializer ()));

        //读取配置文件内的配置,取自RedisCacheConfiguration
        CacheProperties.Redis redisProperties = cacheProperties.getRedis ();
        if (redisProperties.getTimeToLive() != null) {
            config = config.entryTtl(redisProperties.getTimeToLive());
        }
        if (redisProperties.getKeyPrefix() != null) {
            config = config.prefixKeysWith(redisProperties.getKeyPrefix());
        }
        if (!redisProperties.isCacheNullValues()) {
            config = config.disableCachingNullValues();
        }
        if (!redisProperties.isUseKeyPrefix()) {
            config = config.disableKeyPrefix();
        }
        return config;
    }
}

删除缓存

  //简单用法
  @CacheEvict(value = {"categorys"},key = "'getLevel1Categorys'")
    
    
    //调用该方法会删除缓存category下的所有cache,如果要删除某个具体,用key="''"
@Override
@CacheEvict(value = {"category"},allEntries = true)

如果要清空多个缓存,用@Caching(evict={@CacheEvict(value="")})

SpringCache的不足

1)、读模式

缓存穿透:查询一个null数据。解决方案:缓存空数据,可通过spring.cache.redis.cache-null-values=true
缓存击穿:大量并发进来同时查询一个正好过期的数据。解决方案:加锁 ? 默认是无加锁的;
使用sync = true来解决击穿问题
@Cacheable(value = {"categorys"},key = "#root.method.name",sync = true)

缓存雪崩:大量的key同时过期。解决:加随机时间。
spring.cache.redis.time-to-live=3600000

2)、写模式:(缓存与数据库一致)

读写加锁。
引入Canal,感知到MySQL的更新去更新Redis
读多写多,直接去数据库查询就行
3)、总结:

常规数据(读多写少,即时性,一致性要求不高的数据,完全可以使用Spring-Cache):

写模式(只要缓存的数据有过期时间就足够了)

特殊数据:特殊设计

缓存雪崩:大量的key同时过期。解决:加随机时间。
spring.cache.redis.time-to-live=3600000

2)、写模式:(缓存与数据库一致)

读写加锁。
引入Canal,感知到MySQL的更新去更新Redis
读多写多,直接去数据库查询就行
3)、总结:

常规数据(读多写少,即时性,一致性要求不高的数据,完全可以使用Spring-Cache):

写模式(只要缓存的数据有过期时间就足够了)

特殊数据:特殊设计


本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

SpringCache使用 的相关文章

随机推荐

  • 后端跨域问题解决

    出于浏览器的同源策略限制 同源策略 Sameoriginpolicy 是一种约定 它是浏览器最核心也最基本的安全功能 如果缺少了同源策略 则浏览器的正常功能可能都会受到影响 可以说Web是构建在同源策略基础之上的 浏览器只是针对同源策略的一
  • ArrayList扩容机制

    扩容步骤 扩容 把原来的数组复制到另一个内存空间更大的数组中 添加元素 把新元素添加到扩容以后的数组中 2 源码分析 2 1 ArrayList里面的属性 默认初始化容量 private static final int DEFAULT C
  • web基本解题思路

    前两天安装一些web相关的软件 今天主要是做一些简单的web基础题 主要用BurpSuite软件进行抓包和分析数据 其中涉及到一些方法 如下所示 一 爆破 包括包括md5 爆破随机数 验证码识别等 二 绕WAF 包括花式绕Mysql 绕文件
  • Python安装超详细教程

    本文将介绍以下几部分内容 下载 python 安装 python 配置环境变量 python 多版本共存配置 python 编程工具推荐 一 下载 python 下载 python 点击这里进入 python 下载页面 在下载页面可以看到很
  • oracle什么时候要commit,Oracle什么时候需要Commit

    写完DML语句 update insert delete 后 需要手动COMMIT 如果没有COMMIT 更新的内容会被保存到内存中 而不是提交到数据库中 将不会被其他Session 对话 看见 其他对话看到的是更新前的数据 当用户退出对话
  • Docker指定时间段一键过滤容器运行时日志

    文章目录 引 效果 测试输错 时间段模式 时间段方式 时间戳方式 低版本Docker 时间范围模式 实时查看 脚本 引 针对容器日志过多时 过滤某个时间 时间段的日志 效果 说明 针对Docker版本比较低的客户端 无法使用 until参数
  • C#辗转相除法求最大公约数与最小公倍数

    class Program static void Main string args int num1 num2 mm Console WriteLine 请输入第一个数 num1 Convert ToInt32 Console ReadL
  • 【Flutter 1-6】Flutter项目目录结构

    文章首发地址 Flutter项目结构 了解Flutter的目录结构 可以帮助我们更好的管理和开发项目 这样我们在开发的过程中就会很清楚的知道 iOS代码该放在那里 Android代码该放在那里 Flutter代码该放在哪里 测试代码放在哪里
  • Linux操作系统加固

    如何尽可能地加强Linux的安全性和隐私性 以下列出的所有命令都将需要root特权 以 符号开头的单词表示一个变量 不同终端之间可能会有所不同 一 选择正确的Linux发行版 选择一个好的Linux发行版有很多因素 避免分发冻结程序包 因为
  • ubuntu16.04重新编译linux内核

    首先的首先 如果用的是虚拟机 那硬盘至少要分个40G 硬盘太小的后果 你可以试试 一 下载内核 首先到kernel官网获取linux源代码包 我用的ubuntu版本是16 04 因此下载的包可以采用4 x 如果从官网下载速度过慢 我这下载需
  • 日志注入 ctf.show_web4

    使用php input 不行 使用日志注入 查看日志的默认目录 得到了日志文件 url var log nginx access log 进行日志注入 使用蚁剑连接得到flag
  • Acwing 1264. 动态求连续区间和(树状数组版)

    lowbit x x x 返回2 k k为x的二进制表示中末尾0的个数 c x 存的是 x lowbit x x 之间这些数的和 include
  • Django电商项目(四)用户中心、FastDFS

    Django电商项目 用户中心逻辑 登录装饰器和登录后跳转 判断用户是否已登录 退出登录 用户中心 地址页 模型管理器类方法封装 用户中心 个人信息 分布式图片服务器FastDFS 什么是FastDFS 文件上传流程 文件下载流程 简易Fa
  • 区块链在物联网中的应用态势分析

    摘 要 目的 物联网是物体之间共享资源和交流信息的平台 其上的数据价值不断被挖掘显现 而区块链作为一种新型的数据存储管理模式 在体系去中心化 数据溯源和防篡改等方面拥有良好的效果 近来 不少研究都探索了区块链在物联网中的应用 方法 利用文献
  • PaddleHub人体姿态检测模型pose_resnet50_mpii

    姿态检测还是挺有意思的 在 paddlehub 上有直接可以拿来用的模型 pose resnet50 mpii 随便网上找了张图片试了一下效果还行 代码非常简单 import paddlehub as hub module hub Modu
  • Android逆向之旅---爆破一款资讯类应用「最右」防抓包策略原理分析

    一 逆向分析 首先感谢王同学提供的样本 因为王同学那天找到我咨询我说有一个应用Fiddler抓包失败 其实对于这类问题 我一般都会这么回答 第一你是否安装Fiddler证书了 他说他安装了 第二你是否用了我之前说的那个Xposed框架Jus
  • JAVA list加锁_list类里面的东西加锁 (手动加锁方法)

    package privateclass import java util Collection import java util Iterator import java util List import java util ListIt
  • 【计算机组成原理】——原码,反码,补码,移码怎样计算

    机器数与真值 把符号 数字化 的数称为机器数 而把带 或 的数称为真值 正负号用二进制的0 1表示 0 1 x 001 机器数 第一位表示符号 x 1 x 101 真值 直接用 表示 x 5 原码 反码 补码 移码的计算 正数的原码 反码
  • Pycharm绘图时显示额外的“figure”浮窗

    如图所示 不想图片显示在右边 而是单独的一个窗口 这样可以进行点击交互 1 File gt Settings gt 2 找到Tools gt Python Scientific 找到 Python Scientific 去除右边候选框中的勾
  • SpringCache使用

    SpringCache使用 1 引入依赖 引入springcache依赖