SSM之spring注解式缓存redis

本文涉及的产品
RDS MySQL Serverless 基础系列,0.5-2RCU 50GB
云数据库 RDS MySQL,集群系列 2核4GB
推荐场景:
搭建个人博客
Redis 开源版,标准版 2GB
推荐场景:
搭建游戏排行榜
简介: 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
目录
相关文章
|
1月前
|
存储 NoSQL Java
使用lock4j-redis-template-spring-boot-starter实现redis分布式锁
通过使用 `lock4j-redis-template-spring-boot-starter`,我们可以轻松实现 Redis 分布式锁,从而解决分布式系统中多个实例并发访问共享资源的问题。合理配置和使用分布式锁,可以有效提高系统的稳定性和数据的一致性。希望本文对你在实际项目中使用 Redis 分布式锁有所帮助。
121 5
|
2月前
|
消息中间件 NoSQL Java
Spring Boot整合Redis
通过Spring Boot整合Redis,可以显著提升应用的性能和响应速度。在本文中,我们详细介绍了如何配置和使用Redis,包括基本的CRUD操作和具有过期时间的值设置方法。希望本文能帮助你在实际项目中高效地整合和使用Redis。
79 2
|
2月前
|
SQL 缓存 Java
MyBatis如何关闭一级缓存(分注解和xml两种方式)
MyBatis如何关闭一级缓存(分注解和xml两种方式)
91 5
|
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 的前后端分离的后台管理系统
62 0
|
20天前
|
存储 缓存 NoSQL
解决Redis缓存数据类型丢失问题
解决Redis缓存数据类型丢失问题
164 85
|
3月前
|
消息中间件 缓存 NoSQL
Redis 是一个高性能的键值对存储系统,常用于缓存、消息队列和会话管理等场景。
【10月更文挑战第4天】Redis 是一个高性能的键值对存储系统,常用于缓存、消息队列和会话管理等场景。随着数据增长,有时需要将 Redis 数据导出以进行分析、备份或迁移。本文详细介绍几种导出方法:1)使用 Redis 命令与重定向;2)利用 Redis 的 RDB 和 AOF 持久化功能;3)借助第三方工具如 `redis-dump`。每种方法均附有示例代码,帮助你轻松完成数据导出任务。无论数据量大小,总有一款适合你。
87 6
|
17天前
|
缓存 监控 NoSQL
Redis经典问题:缓存穿透
本文详细探讨了分布式系统和缓存应用中的经典问题——缓存穿透。缓存穿透是指用户请求的数据在缓存和数据库中都不存在,导致大量请求直接落到数据库上,可能引发数据库崩溃或性能下降。文章介绍了几种有效的解决方案,包括接口层增加校验、缓存空值、使用布隆过滤器、优化数据库查询以及加强监控报警机制。通过这些方法,可以有效缓解缓存穿透对系统的影响,提升系统的稳定性和性能。
|
2月前
|
缓存 NoSQL 关系型数据库
大厂面试高频:如何解决Redis缓存雪崩、缓存穿透、缓存并发等5大难题
本文详解缓存雪崩、缓存穿透、缓存并发及缓存预热等问题,提供高可用解决方案,帮助你在大厂面试和实际工作中应对这些常见并发场景。关注【mikechen的互联网架构】,10年+BAT架构经验倾囊相授。
大厂面试高频:如何解决Redis缓存雪崩、缓存穿透、缓存并发等5大难题
|
2月前
|
存储 缓存 NoSQL
【赵渝强老师】基于Redis的旁路缓存架构
本文介绍了引入缓存后的系统架构,通过缓存可以提升访问性能、降低网络拥堵、减轻服务负载和增强可扩展性。文中提供了相关图片和视频讲解,并讨论了数据库读写分离、分库分表等方法来减轻数据库压力。同时,文章也指出了缓存可能带来的复杂度增加、成本提高和数据一致性问题。
【赵渝强老师】基于Redis的旁路缓存架构
|
2月前
|
缓存 NoSQL Redis
Redis 缓存使用的实践
《Redis缓存最佳实践指南》涵盖缓存更新策略、缓存击穿防护、大key处理和性能优化。包括Cache Aside Pattern、Write Through、分布式锁、大key拆分和批量操作等技术,帮助你在项目中高效使用Redis缓存。
363 22
下一篇
开通oss服务