“Redis与Spring整合及缓存优化“

news2024/11/22 20:50:34

文章目录

  • 引言
  • 1. Spring整合Redis
    • 1.1. 为什么选择Redis作为缓存解决方案?
      • Redis的特点和优势
      • Redis与传统关系数据库的对比
    • 1.2. Spring与Redis整合的基本步骤
  • 2. Redis注解式缓存
    • 2.1. Spring提供的缓存注解介绍
    • 2.2. 使用注解实现方法级别的缓存
  • 3. Redis的击穿、穿透和雪崩问题及解决方案
    • 3.1. 几种常见的Redis缓存问题
    • 3.2. 解决方案和优化策略
  • 总结

在这里插入图片描述

引言

在现代应用开发中,缓存是提升性能和扩展性的关键技术之一。而Redis作为一种高性能、内存存储型数据库,与Spring框架的结合可以带来更加优雅和灵活的缓存解决方案。本篇博客将深入探讨Spring整合Redis的方法和最佳实践,并重点介绍Redis注解式缓存以及解决常见的Redis问题。

1. Spring整合Redis

1.1. 为什么选择Redis作为缓存解决方案?

Redis的特点和优势

  • 内存存储:Redis将数据存储在内存中,因此具有非常高的读写速度。相比传统数据库的磁盘存储,Redis能够快速处理大量请求。

  • 键值存储:Redis使用键值对(key-value)的数据结构来存储数据。这种简单的数据模型使得数据操作非常高效和灵活,适用于各种场景。

  • 支持多种数据类型:Redis支持丰富的数据类型,包括字符串、哈希、列表、集合、有序集合等。这些数据类型的支持使得开发者可以更方便地构建复杂的应用逻辑。

  • 缓存功能:Redis常被用作缓存服务器,可以将频繁访问的数据存储在内存中,从而加快数据读取速度。同时,Redis还提供了一些高级的缓存策略,如过期时间、LRU淘汰等。

  • 发布订阅系统:Redis提供了发布订阅(pub/sub)功能,允许客户端通过订阅某个频道来接收消息的推送。这种消息发布订阅模式对于实时通信、消息队列等场景非常有用。

  • 分布式支持:Redis支持分布式部署,可以将数据分布在多个节点上进行存储和访问。这种分布式的特性使得Redis具备高可用性和横向扩展的能力。

Redis与传统关系数据库的对比

  • 数据模型:Redis采用键值对的数据模型,而传统关系数据库使用表格模型。这使得Redis在处理简单查询和高并发读写方面更加高效,而关系数据库更适合复杂的数据关联和查询操作。

  • 存储方式:Redis将数据存储在内存中,而关系数据库通常将数据持久化到磁盘中。因此,Redis在读写速度方面更快,但关系数据库在数据持久化和容量方面具有优势。

  • 功能特性:Redis提供了丰富的功能特性,如发布订阅、缓存策略等,而关系数据库更加注重数据一致性、事务管理以及复杂的查询能力。

  • 扩展性:Redis支持分布式部署和横向扩展,可以通过添加新的节点来提高性能和容量。而关系数据库通常需要进行垂直扩展,即增加更强大的硬件来应对高负载。

  • 数据一致性:Redis默认情况下是单机的,不保证数据的强一致性,而关系数据库通常会保证数据的一致性。

1.2. Spring与Redis整合的基本步骤

准备步骤:

  1. 打开redis服务
  2. 导入spring整合redis项目
  • 当spring-context.xml文件需要注册多个.properties结尾的配置文件,不能在spring-*中添加注册

applicationContext.xml

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:context="http://www.springframework.org/schema/context" xmlns:tx="http://www.springframework.org/schema/tx"
       xmlns:aop="http://www.springframework.org/schema/aop"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd">
    <!--1. 引入外部多文件方式 -->
    <bean id="propertyConfigurer"
          class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
        <property name="systemPropertiesModeName" value="SYSTEM_PROPERTIES_MODE_OVERRIDE" />
        <property name="ignoreResourceNotFound" value="true" />
        <property name="locations">
            <list>
                <value>classpath:jdbc.properties</value>
                <value>classpath:redis.properties</value>
            </list>
        </property>
    </bean>

<!--  随着后续学习,框架会越学越多,不能将所有的框架配置,放到同一个配制间,否者不便于管理  -->
    <import resource="applicationContext-mybatis.xml"></import>
    <import resource="spring-redis.xml"></import>
    <import resource="applicationContext-shiro.xml"></import>
</beans>

redis.properties

redis.hostName=localhost
redis.port=6379
redis.password=123456
redis.timeout=10000
redis.maxIdle=300
redis.maxTotal=1000
redis.maxWaitMillis=1000
redis.minEvictableIdleTimeMillis=300000
redis.numTestsPerEvictionRun=1024
redis.timeBetweenEvictionRunsMillis=30000
redis.testOnBorrow=true
redis.testWhileIdle=true
redis.expiration=3600

spring-redis.xml

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:context="http://www.springframework.org/schema/context"
       xmlns:cache="http://www.springframework.org/schema/cache"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
       http://www.springframework.org/schema/beans/spring-beans.xsd
       http://www.springframework.org/schema/context
       http://www.springframework.org/schema/context/spring-context.xsd
       http://www.springframework.org/schema/cache
       http://www.springframework.org/schema/cache/spring-cache.xsd">

    <!-- 1. 引入properties配置文件 -->
    <!--<context:property-placeholder location="classpath:redis.properties" />-->

    <!-- 2. redis连接池配置-->
    <bean id="poolConfig" class="redis.clients.jedis.JedisPoolConfig">
        <!--最大空闲数-->
        <property name="maxIdle" value="${redis.maxIdle}"/>
        <!--连接池的最大数据库连接数  -->
        <property name="maxTotal" value="${redis.maxTotal}"/>
        <!--最大建立连接等待时间-->
        <property name="maxWaitMillis" value="${redis.maxWaitMillis}"/>
        <!--逐出连接的最小空闲时间 默认1800000毫秒(30分钟)-->
        <property name="minEvictableIdleTimeMillis" value="${redis.minEvictableIdleTimeMillis}"/>
        <!--每次逐出检查时 逐出的最大数目 如果为负数就是 : 1/abs(n), 默认3-->
        <property name="numTestsPerEvictionRun" value="${redis.numTestsPerEvictionRun}"/>
        <!--逐出扫描的时间间隔(毫秒) 如果为负数,则不运行逐出线程, 默认-1-->
        <property name="timeBetweenEvictionRunsMillis" value="${redis.timeBetweenEvictionRunsMillis}"/>
        <!--是否在从池中取出连接前进行检验,如果检验失败,则从池中去除连接并尝试取出另一个-->
        <property name="testOnBorrow" value="${redis.testOnBorrow}"/>
        <!--在空闲时检查有效性, 默认false  -->
        <property name="testWhileIdle" value="${redis.testWhileIdle}"/>
    </bean>

    <!-- 3. redis连接工厂 -->
    <bean id="connectionFactory" class="org.springframework.data.redis.connection.jedis.JedisConnectionFactory"
          destroy-method="destroy">
        <property name="poolConfig" ref="poolConfig"/>
        <!--IP地址 -->
        <property name="hostName" value="${redis.hostName}"/>
        <!--端口号  -->
        <property name="port" value="${redis.port}"/>
        <!--如果Redis设置有密码  -->
        <property name="password" value="${redis.password}"/>
        <!--客户端超时时间单位是毫秒  -->
        <property name="timeout" value="${redis.timeout}"/>
    </bean>

    <!-- 4. redis操作模板,使用该对象可以操作redis
        hibernate课程中hibernatetemplete,相当于session,专门操作数据库。
    -->
    <bean id="redisTemplate" class="org.springframework.data.redis.core.RedisTemplate">
        <property name="connectionFactory" ref="connectionFactory"/>
        <!--如果不配置Serializer,那么存储的时候缺省使用String,如果用User类型存储,那么会提示错误User can't cast to String!!  -->
        <property name="keySerializer">
            <bean class="org.springframework.data.redis.serializer.StringRedisSerializer"/>
        </property>
        <property name="valueSerializer">
            <bean class="org.springframework.data.redis.serializer.GenericJackson2JsonRedisSerializer"/>
        </property>
        <property name="hashKeySerializer">
            <bean class="org.springframework.data.redis.serializer.StringRedisSerializer"/>
        </property>
        <property name="hashValueSerializer">
            <bean class="org.springframework.data.redis.serializer.GenericJackson2JsonRedisSerializer"/>
        </property>
        <!--开启事务  -->
        <property name="enableTransactionSupport" value="true"/>
    </bean>

    <!--  5.配置缓存管理器  -->
    <bean id="redisCacheManager" class="org.springframework.data.redis.cache.RedisCacheManager">
        <constructor-arg name="redisOperations" ref="redisTemplate"/>
        <!--redis缓存数据过期时间单位秒-->
        <property name="defaultExpiration" value="${redis.expiration}"/>
        <!--是否使用缓存前缀,与cachePrefix相关-->
        <property name="usePrefix" value="true"/>
        <!--配置缓存前缀名称-->
        <property name="cachePrefix">
            <bean class="org.springframework.data.redis.cache.DefaultRedisCachePrefix">
                <constructor-arg index="0" value="-cache-"/>
            </bean>
        </property>
    </bean>

    <!--6.配置缓存生成键名的生成规则-->
    <bean id="cacheKeyGenerator" class="com.zking.ssm.redis.CacheKeyGenerator"></bean>

    <!--7.启用缓存注解功能-->
    <cache:annotation-driven cache-manager="redisCacheManager" key-generator="cacheKeyGenerator"/>
</beans>
  • resources的配置文件的配置必须要涵盖读取.properties结尾的文件
    在这里插入图片描述
  • redisTemplate的使用,可以参照jdbcTemplate、amqpTemplate、rabbitMQtemplate等

2. Redis注解式缓存

2.1. Spring提供的缓存注解介绍

package com.zking.ssm.biz;

import com.zking.ssm.model.Clazz;
import com.zking.ssm.util.PageBean;
import org.springframework.cache.annotation.CacheEvict;
import org.springframework.cache.annotation.CachePut;

import java.util.List;
import java.util.Map;

public interface ClazzBiz {
    @CacheEvict(value = "xx",key = "'cid:'+#cid",allEntries = true)
    int deleteByPrimaryKey(Integer cid);

    int insert(Clazz record);

    int insertSelective(Clazz record);

//    xx=cache-cid:1
//    key的作用改变原有的key生成规则
//    @Cacheable(value = "xx",key = "'cid:'+#cid",condition = "#cid > 6")
    @CachePut(value = "xx",key = "'cid:'+#cid",condition = "#cid > 6")
    Clazz selectByPrimaryKey(Integer cid);

    int updateByPrimaryKeySelective(Clazz record);

    int updateByPrimaryKey(Clazz record);

    List<Clazz> listPager(Clazz clazz, PageBean pageBean);
    List<Map> listMapPager(Clazz clazz, PageBean pageBean);
}

@Cacheable:缓存方法的返回值,可读写
@CachePut:更新缓存的方法,只写不读,适合读写分离
@CacheEvict:移除缓存中的数据

2.2. 使用注解实现方法级别的缓存

在Spring Boot项目中开启注解式缓存
定义缓存的Key和Value的生成策略
编写示例代码演示注解式缓存的使用方式

3. Redis的击穿、穿透和雪崩问题及解决方案

在这里插入图片描述

3.1. 几种常见的Redis缓存问题

击穿:大量请求同时查询一个不存在的Key,导致请求都落到数据库上
穿透:恶意请求查询一个不存在的Key,导致请求直接落到数据库上
雪崩:大量缓存失效导致所有请求都落到数据库上

3.2. 解决方案和优化策略

击穿解决方案:设置热点数据永不过期、互斥锁、布隆过滤器等
穿透解决方案:空值缓存、参数校验、布隆过滤器等
雪崩解决方案:限流、降级、异步更新缓存等

总结

在本篇博客中,我们深入探讨了Redis与Spring的整合以及注解式缓存的使用方式。通过学习和实践,我们了解了Redis作为一种高性能缓存解决方案的优势,并且掌握了基于Spring框架使用Redis的方法。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1180339.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

系统有同类资源m个,供n个进程共享,若每个进程对资源的最大需求量为k,试问:当m,n,k的值分别为下列情况时(见下表),是否会发生死锁?

一.系统有同类资源m个&#xff0c;供n个进程共享&#xff0c;若每个进程对资源的最大需求量为k&#xff0c;试问&#xff1a;当m,n,k的值分别为下列情况时&#xff08;见下表&#xff09;&#xff0c;是否会发生死锁&#xff1f; &#xff08;1&#xff09;m6;n3;k3 &#xf…

shopee买家通系统一款全自动化操作的软件

Shopee买家通系统可以批量注册虾皮买家号、自动加购加心愿单、根据关键词及产品编号搜索下单。 想要注册虾皮买家号&#xff0c;准备好相应国家的手机号及ip即可&#xff0c;准备好之后按照软件所需格式添加后即可运行自动化注册&#xff0c;注册时可以自动输入手机号、自动接…

linux服务器国内源安装nvm,又快又方便

国内安装nvm的话&#xff0c;如果你的服务器不能访问github&#xff0c;那么使用gitee快速安装还是很方便的&#xff1a; # 能方位github的话&#xff0c;使用这条命令 curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.39.2/install.sh | bash# 不能访问github的话…

延长千倍!美国阿贡实验室量子比特相干时间新纪录

两个具有长相干时间并强耦合的量子比特&#xff08;图片来源&#xff1a;网络&#xff09; 在书面语、口语以及信息处理领域&#xff0c;连贯性均是实现有效沟通的关键要素&#xff0c;这同样适用于量子比特。 美国能源部&#xff08;DOE&#xff09;下属的阿贡国家实验室所领…

计算机毕业设计java+springboot+vue的在线考试系统

项目介绍 具体在系统设计上&#xff0c;采用了B/S的结构&#xff0c;同时&#xff0c;也使用Java技术在动态页面上进行了设计&#xff0c;后台上采用Mysql数据库&#xff0c;是一个非常优秀的青少年编程在线考试系统。 开发环境 开发语言&#xff1a;Java 后端框架&#xff…

SpirngBoot做H5支付 JSSDK支付 为uniapp小程序提供接口 详细内容包含支付、退款以及支付退款回调 纯微信支付V2支付 最后附上完整代码

可以先看一下下面的IndexController 先理解一下需要用到哪些参数然后再从头开始准备就不会一头蒙了 完整代码&#xff1a; 链接: https://pan.quark.cn/s/518e02b22e4f 提取码&#xff1a;J6f2 可能遇到的坑&#xff1a; 微信支付这个的文档可以说跟没有是一样的 只写入参回…

【HMS Core】推送热门合集4

【问题描述1】 如果云端通知的category&#xff0c;本地通知不支持&#xff0c;如何处理&#xff1f; 【解决方案】 如果云端通知的category&#xff0c;本地通知不支持&#xff0c;或者云端通知的category的取值在分类标准中是不涉及&#xff0c;那么说明该类型不支持本地通…

工业物联网网关解决方案openwrt二次开发无线路由WiFi模块选型

在现今高科技快速发展的时代&#xff0c;无线通信技术已经成为人们日常生活中不可或缺的一部分。而在众多的无线技术产品中&#xff0c;基于IEEE 802.11系列协议的WiFi技术无疑是其中的主流。随着WiFi技术的广泛应用&#xff0c;市面上涌现出了各种各样的主控平台和WiFi模块。今…

魔众文库系统 v5.5.0 批量快捷上传,文档图标优化,档转换逻辑优化

魔众文库系统基于文档系统知识&#xff0c;建立平台与领域&#xff0c;打造流量、用户、付费和变现的闭环&#xff0c;帮助您更好的搭建文库系统。 魔众文库系统发布v5.5.0版本&#xff0c;新功能和Bug修复累计14项&#xff0c;批量快捷上传&#xff0c;文档图标优化&#xff…

JQ完成模拟QQ好友分组案例(介绍JQ实现原理)

当我们写这个案例之前&#xff0c;需要引入好JQ文件&#xff0c;以防没有效果 这个案例的需求请看以下效果图 不能重复点击&#xff0c;只有删除掉之后才可以继续点击 效果图&#xff1a; 代码介绍&#xff1a; <!DOCTYPE html> <html lang"en"><h…

【每日一题】2586. 统计范围内的元音字符串数-2023.11.7

题目&#xff1a; 2586. 统计范围内的元音字符串数 给你一个下标从 0 开始的字符串数组 words 和两个整数&#xff1a;left 和 right 。 如果字符串以元音字母开头并以元音字母结尾&#xff0c;那么该字符串就是一个 元音字符串 &#xff0c;其中元音字母是 a、e、i、o、u 。…

Python采集数据代码示例

基本的爬虫程序的示例&#xff1a; typescript import * as request from request; // 信息 const proxyHost ; const proxyPort ; // 网站的 URL const url ; // 使用 request 库发起请求 request({ url, method: GET, proxy: { host: proxyHost…

vue递归获取树形菜单

文章目录 前言什么是递归&#xff1f; 一、数据集二、 递归函数三、打印树形结构展示 前言 什么是递归&#xff1f; 程序调用自身的编程技巧称为递归&#xff08; recursion&#xff09;。 递归 粗略的理解为 循环 &#xff0c;只不过 递归 是调用自身。 在实际使用中&#xf…

libwebsockets入门

WebSocket是一种在单个TCP连接上进行全双工通讯的协议&#xff0c;用于在Web客户端和服务器之间建立持久连接&#xff0c;进行实时通信。它是HTML5开始提供的一种通讯方式&#xff0c;通过使用WebSocket连接&#xff0c;web应用程序可以执行实时的交互&#xff0c;而不是以前的…

将json数据转换为Python字典

import requests from bs4 import BeautifulSoup import json# 定义代理信息 proxy_host www.duoip.cn proxy_port 8000# 定义要爬取的url url http://localhost:9200/_search# 创建一个requests.Session对象&#xff0c;并设置代理 session requests.Session() session.pr…

Python3,3行代码,给照片填充背景色,从此跟照相馆说拜拜。

3行代码照片上背景色 1、引言2、代码实战2.1 思路2.2 安装2.3 实例 3、总结 1、引言 小屌丝&#xff1a; 鱼哥&#xff0c;帮个忙。 小鱼&#xff1a; 在开车。 小屌丝&#xff1a;… 那你先忙&#xff0c;不打扰你了。 小鱼&#xff1a;…我可以说话的&#xff0c;没事。 小屌…

3.4、Linux小程序:进度条

个人主页&#xff1a;Lei宝啊 愿所有美好如期而遇 目录 回车与换行的概念和区别 行缓冲区概念 进度条代码 version1 version2 version3 回车与换行的概念和区别 换行\n&#xff0c;回车\r 似乎无需多言 行缓冲区概念 这里我们通过例子来简单理解即可&#xff0c;深入…

Wait-Notify机制

文章目录 1. 简介2. 相关API3. wait notify的正确姿势4. 总结 1. 简介 回顾Minitor锁的结构&#xff1a; Owner线程发现条件不满足&#xff0c;调用wait方法&#xff0c;即可进入WaitSet变为WAITING状态BLOCKED和WAITING的线程都处于阻塞状态&#xff0c;不占用CPU时间BLOCK…

新浪微博一键删除所有内容

亲自测试用 具体操作如下&#xff1a; 对应的 1 2 如下&#xff0c;进入这个界面是按F12 就可以看到 最后画横线的位置 替换自己的id 对应的就是 3 具体代码如下 //向删除接口发起请求&#xff0c;删除对应节点 function del_weibo(id) {var myHeaders new Headers();myHea…

小白学爬虫:通过商品ID获取1688跨境属性数据接口|1688商品属性接口|1688一件代发数据接口|1688商品详情接口

通过商品ID获取1688跨境属性数据接口可以使用1688开放平台提供的API接口实现。以下是获取跨境属性数据的基本步骤&#xff1a; 点击获取测试key和secret构造请求参数&#xff0c;包括商品ID和其他必要参数&#xff0c;如接口权限、请求类型等。通过API接口链接&#xff0c;将请…