SSM之spring注解式缓存redis

本文涉及的产品
Redis 开源版,标准版 2GB
推荐场景:
搭建游戏排行榜
云数据库 Tair(兼容Redis),内存型 2GB
RDS MySQL Serverless 基础系列,0.5-2RCU 50GB
简介: SSM之spring注解式缓存redis

SSM(Spring + SpringMVC + MyBatis)是一种常用的 Java Web 开发框架,而 Redis 是一种常用的 NoSQL 数据库。在 SSM 框架中,可以通过整合 Redis 来实现数据缓存、分布式锁等功能,提高系统的性能和可靠性。

SSM整合redis

Redis 和 MySQL 是两种不同类型的数据库,下面是它们之间的主要区别:

1.数据存储方式:Redis 是一种基于键值对存储的内存数据库,而 MySQL 是一种基于表的关系型数据库。


2.数据查询语言:Redis 是一种 NoSQL 数据库,不支持 SQL 语言,没有像 SQL 那样的复杂查询语句,而 MySQL 支持 SQL 语言,可以进行复杂的查询操作。


3.数据存储方式:Redis 数据以键值对的方式进行存储,可以存储多种数据类型,如字符串、哈希、列表、集合、有序集合等。MySQL 则基于表的数据模型进行存储,支持多种数据类型,如整型、字符型、日期型等。


4.数据库容量:Redis 基于内存存储,数据容量有限,适用于存储较小量的数据。MySQL 支持大容量的存储,适合存储大量数据。


5.数据库性能:Redis 基于内存存储,读写速度极快,通常可以支持高并发访问,适合实时数据读写操作。MySQL 则需要通过硬盘进行存储和读写操作,速度相对较慢,但对于复杂的数据处理,MySQL 的性能通常比 Redis 更优。


综上所述,Redis 和 MySQL 分别适用于不同的应用场景,需要结合具体业务需求进行选择。


可以去参考整合mysql,即整合mybatis


1.pom配置


2.spring-mydatis.xml -->mybatis.cfg.xml


               1.包扫描


               2.注册一个jdbc.properties


               3.配置数据源(数据连接池)


               4.配置sqlsession,配置会话


               5.配置事务。。。


3.springContext.xml中添加spring-mybatis.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="300"/>
        <!--连接池的最大数据库连接数  -->
        <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>

整合redis

1. pom配置

2.spring-redis.xml

               1.注册了一个redis.properties

            2.配置数据源(数据库连接池)


               3.连接工厂


               4.配置序列化器


               5.配置redis的key生成策略


3.springContext.xml中添加spring-redis.xml

导入

导入我们的SSM项目,在我们的导入项目的时候开启服务

查看我们的配置

注意1:当spring-comtext.xml中需要注册多个.properties结尾的配置文件,那么不能在spring-*.xml添加注册


注意2:resources的配置必须要涵盖读取.properties结尾的文件


注意3:redisTemplate的使用,可以参照jdbcTemplate,new Jedi(ip,port).auth().get


pom
  <properties>    
    <redis.version>2.9.0</redis.version>
    <redis.spring.version>1.7.1.RELEASE</redis.spring.version>
  </properties>
  <dependencies>
    <dependency>
      <groupId>redis.clients</groupId>
      <artifactId>jedis</artifactId>
      <version>${redis.version}</version>
    </dependency>
    <dependency>
      <groupId>org.springframework.data</groupId>
      <artifactId>spring-data-redis</artifactId>
      <version>${redis.spring.version}</version>
    </dependency>
  </dependencies>
redis.properties配置
redis.hostName=47.100.191.44
redis.port=6379
redis.password=xiaoli_redis
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

 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>

注解式开发及应用场景

注解式开发是一种基于注解的编程模型,它允许在代码中声明注解,以此来描述应用程序的元素和行为。注解式开发可以提高代码的可读性、可维护性和可扩展性,常用于各种框架和库中,如Spring、Hibernate、JUnit等。

以下是注解式开发应用的一些场景:

  1. 配置和管理对象声明:通过注解来描述对象的属性和行为,可以减少配置文件的数量和复杂度,同时也提高了代码的可读性和可维护性。
  2. 实现声明式事务处理:在方法上使用注解来声明事务的属性和行为,可以使事务处理更加简单和可控。
  3. 实现依赖注入:注解可以用于标记需要注入的对象或属性,从而使依赖注入更加简单和灵活。
  4. 执行AOP切面:通过注解来声明切面和切点,可以在运行时动态地织入切面。
  5. 描述测试用例:通过注解来描述测试用例的属性和行为,可以使测试代码更加简洁和可读。

总之,注解式开发的应用场景非常广泛,可以在各种类型的应用程序中使用,从而提高代码的可维护性和可扩展性。

@Cacheable

@Cacheable是Spring框架中的一个注解,用于将方法的返回值缓存起来,以提高应用程序的性能。当在相同参数下再次调用该方法时,会直接从缓存中获取结果,而不是重新执行一遍方法。


@Cacheable可以标注在类或方法上。当标注在类上时,表示该类的所有方法都可以被缓存。当标注在方法上时,表示该方法可以被缓存。


@Cacheable可以设置以下属性:


  • value:缓存的名称,必填项。
  • key:缓存的键值,可以使用SpEL表达式,缺省值为方法的所有参数。
  • condition:缓存的条件,可以使用SpEL表达式,缺省值为“true”。
  • unless:缓存的结果是否需要反向存储,可以使用SpEL表达式。

以下是一个使用@Cacheable注解的示例:

@Cacheable(value = "myCache", key = "#id") public User getUserById(String id) { User user = userRepository.findById(id); return user; }

在这个示例中,getUserById方法的返回值会被缓存起来,并放入名称为“myCache”的缓存中,缓存的键值为方法的参数id。当再次调用该方法时,如果参数id相同,则直接从缓存中获取结果,而不是重新执行一遍方法。

@CachePut

@CachePut是Spring框架中的一个注解,用于更新缓存中的数据。与@Cacheable注解不同的是,@CachePut注解无论缓存中是否存在对应的数据,都会执行方法并将返回值更新到缓存中。


@CachePut可以标注在类或方法上。当标注在类上时,表示该类的所有方法都可以被更新缓存。当标注在方法上时,表示该方法可以更新缓存。


@CachePut可以设置以下属性:


  • value:缓存的名称,必填项。
  • key:缓存的键值,可以使用SpEL表达式,缺省值为方法的所有参数。
  • condition:缓存的条件,可以使用SpEL表达式,缺省值为“true”。
  • unless:缓存的结果是否需要反向存储,可以使用SpEL表达式。

以下是一个使用@CachePut注解的示例:

@CachePut(value = "myCache", key = "#id") public User updateUserById(String id, User user) { userRepository.updateById(id, user); return user; }

在这个示例中,updateUserById方法会更新数据库中的数据,并将更新后的User对象放入名称为“myCache”的缓存中,缓存的键值为方法的参数id。无论缓存中是否存在对应的数据,都会执行该方法并更新缓存。

@CacheEvict

@CacheEvict是Spring框架中的一个注解,用于从缓存中删除数据。当我们更新或删除数据时,需要将缓存中的数据同步删除,避免脏数据的出现,这时可以使用@CacheEvict注解。


@CacheEvict可以标注在类或方法上。当标注在类上时,表示该类的所有方法都可以被删除缓存。当标注在方法上时,表示该方法可以删除缓存。


@CacheEvict可以设置以下属性:


  • value:缓存的名称,必填项。
  • key:缓存的键值,可以使用SpEL表达式,缺省值为方法的所有参数。
  • condition:删除缓存的条件,可以使用SpEL表达式,缺省值为“true”。
  • allEntries:是否删除缓存中的所有数据,缺省值为false。

以下是一个使用@CacheEvict注解的示例:

@CacheEvict(value = "myCache", key = "#id") public void deleteUserById(String id) { userRepository.deleteById(id); }

在这个示例中,deleteUserById方法会从数据库中删除对应的数据,并将名称为“myCache”、键值为id的缓存数据删除。如果allEntries属性设置为true,则会删除“myCache”中所有的数据。

击穿、穿透、雪崩

这三个术语都是与缓存相关的问题。

击穿

击穿指的是一个非常热点的数据在缓存中失效,此时大量请求直接请求到数据库,导致数据库压力骤增,进而导致系统性能急剧下降。通常的解决方案是设置热点数据永远不过期,或者使用互斥锁(比如Redis中的SETNX),只允许一个线程去更新缓存。


常见的解决方案有两种:


互斥锁


逻辑过期

穿透

穿透则是指请求的数据在缓存中不存在,且数据库中也不存在,这样大量请求会直接透过缓存请求到数据库上,造成数据库压力增大,系统性能下降。为避免这种情况,可以在缓存中加入空对象,并设置一个较短的过期时间,这样请求队列中的请求在得到空对象后就不会再去请求数据库。

解决方案

缓存null值

布隆过滤

增强id的复杂度,避免被猜测id规律

做好数据的基础格式校验

加强用户权限校验

做好热点参数的限流

雪崩

雪崩是指缓存中的大量数据同时失效,导致一大批请求直接访问数据库,造成数据库瞬间压力过大,系统崩溃。为了避免这种情况,可以在缓存中设置不同的过期时间,使得不同的数据在不同的时间失效,从而减轻数据库的压力。同时,可以设置本地缓存或者分布式锁来避免缓存失效时大量请求同时访问数据库的情况。


解决方案:


给不同的Key的TTL添加随机值


利用Redis集群提高服务的可用性


给缓存业务添加降级限流策略


给业务添加多级缓存

相关实践学习
基于Redis实现在线游戏积分排行榜
本场景将介绍如何基于Redis数据库实现在线游戏中的游戏玩家积分排行榜功能。
云数据库 Redis 版使用教程
云数据库Redis版是兼容Redis协议标准的、提供持久化的内存数据库服务,基于高可靠双机热备架构及可无缝扩展的集群架构,满足高读写性能场景及容量需弹性变配的业务需求。 产品详情:https://www.aliyun.com/product/kvstore &nbsp; &nbsp; ------------------------------------------------------------------------- 阿里云数据库体验:数据库上云实战 开发者云会免费提供一台带自建MySQL的源数据库&nbsp;ECS 实例和一台目标数据库&nbsp;RDS实例。跟着指引,您可以一步步实现将ECS自建数据库迁移到目标数据库RDS。 点击下方链接,领取免费ECS&amp;RDS资源,30分钟完成数据库上云实战!https://developer.aliyun.com/adc/scenario/51eefbd1894e42f6bb9acacadd3f9121?spm=a2c6h.13788135.J_3257954370.9.4ba85f24utseFl
目录
相关文章
|
13天前
|
Java Spring
在使用Spring的`@Value`注解注入属性值时,有一些特殊字符需要注意
【10月更文挑战第9天】在使用Spring的`@Value`注解注入属性值时,需注意一些特殊字符的正确处理方法,包括空格、引号、反斜杠、新行、制表符、逗号、大括号、$、百分号及其他特殊字符。通过适当包裹或转义,确保这些字符能被正确解析和注入。
|
2天前
|
XML JSON Java
SpringBoot必须掌握的常用注解!
SpringBoot必须掌握的常用注解!
14 4
SpringBoot必须掌握的常用注解!
|
4天前
|
存储 缓存 Java
Spring缓存注解【@Cacheable、@CachePut、@CacheEvict、@Caching、@CacheConfig】使用及注意事项
Spring缓存注解【@Cacheable、@CachePut、@CacheEvict、@Caching、@CacheConfig】使用及注意事项
27 2
|
4天前
|
JSON Java 数据库
SpringBoot项目使用AOP及自定义注解保存操作日志
SpringBoot项目使用AOP及自定义注解保存操作日志
19 1
|
2天前
|
JavaScript NoSQL Java
CC-ADMIN后台简介一个基于 Spring Boot 2.1.3 、SpringBootMybatis plus、JWT、Shiro、Redis、Vue quasar 的前后端分离的后台管理系统
CC-ADMIN后台简介一个基于 Spring Boot 2.1.3 、SpringBootMybatis plus、JWT、Shiro、Redis、Vue quasar 的前后端分离的后台管理系统
18 0
|
11天前
|
存储 Java 数据管理
强大!用 @Audited 注解增强 Spring Boot 应用,打造健壮的数据审计功能
本文深入介绍了如何在Spring Boot应用中使用`@Audited`注解和`spring-data-envers`实现数据审计功能,涵盖从添加依赖、配置实体类到查询审计数据的具体步骤,助力开发人员构建更加透明、合规的应用系统。
|
2月前
|
SQL 监控 druid
springboot-druid数据源的配置方式及配置后台监控-自定义和导入stater(推荐-简单方便使用)两种方式配置druid数据源
这篇文章介绍了如何在Spring Boot项目中配置和监控Druid数据源,包括自定义配置和使用Spring Boot Starter两种方法。
|
关系型数据库 Java MySQL
SSM-Spring-20:Spring中事务基础
  ------------吾亦无他,唯手熟尔,谦卑若愚,好学若饥-------------       事务 事务是什么?   我记得当初的百度百科上讲,事务是执行的最小逻辑单元,它们要么都执行,要么都不执行   (同生共死) 事务解决什么问题?   简单的提一个小例子,...
1266 0
|
23天前
|
人工智能 自然语言处理 前端开发
SpringBoot + 通义千问 + 自定义React组件:支持EventStream数据解析的技术实践
【10月更文挑战第7天】在现代Web开发中,集成多种技术栈以实现复杂的功能需求已成为常态。本文将详细介绍如何使用SpringBoot作为后端框架,结合阿里巴巴的通义千问(一个强大的自然语言处理服务),并通过自定义React组件来支持服务器发送事件(SSE, Server-Sent Events)的EventStream数据解析。这一组合不仅能够实现高效的实时通信,还能利用AI技术提升用户体验。
125 2
|
3月前
|
缓存 Java Maven
Java本地高性能缓存实践问题之SpringBoot中引入Caffeine作为缓存库的问题如何解决
Java本地高性能缓存实践问题之SpringBoot中引入Caffeine作为缓存库的问题如何解决