SpringBoot集成Redis作数据缓存

本文涉及的产品
Redis 开源版,标准版 2GB
推荐场景:
搭建游戏排行榜
云数据库 Tair(兼容Redis),内存型 2GB
简介: SpringBoot集成Redis作数据缓存


@[Toc]


一、缓存简介

Spring 3.1 引入了激动人心的基于注释(annotation)的缓存(cache)技术,它本质上不是一个具体的缓存实现方案(例如 EHCache 或者 Redis),而是一个对缓存使用的抽象,通过在既有代码中添加少量它定义的各种 annotation,即能够达到缓存方法的返回对象的效果。

目前 Spring Boot 支持的缓存有如下几种:

  • JCache (JSR-107)
  • EhCache 2.x
  • Hazelcast
  • lnfinispan
  • Couchbase
  • Redis
  • Caffeine
  • Simple

目前常用的缓存实现 Ehcache 2.x和 Redis。由于 Spring 早己将缓存领域统一 ,因此无论使用哪种缓存实现,不同的只是缓存配置,开发者使用的缓存注解是一致的( Spring 缓存注解和各缓存实现的关系就像 JDBC和各种数据库驱动的关系)。

这里学习使用Redis作为缓存实现。


二、Redis缓存


1、添加依赖

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
<dependency>
    <groupId>org.apache.commons</groupId>
    <artifactId>commons-pool2</artifactId>
</dependency>
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-test</artifactId>
    <scope>test</scope>
</dependency>


2、属性配置

在application.properties中添加配置:

spring.redis.host=localhost
spring.redis.password=
# 一般来说是不用配置的,Spring Cache 会根据依赖的包自行装配
spring.cache.type=redis
# 连接超时时间(毫秒)
spring.redis.timeout=10000
# Redis默认情况下有16个分片,这里配置具体使用的分片
spring.redis.database=0
# 连接池最大连接数(使用负值表示没有限制) 默认 8
spring.redis.lettuce.pool.max-active=8
# 连接池最大阻塞等待时间(使用负值表示没有限制) 默认 -1
spring.redis.lettuce.pool.max-wait=-1
# 连接池中的最大空闲连接 默认 8
spring.redis.lettuce.pool.max-idle=8
# 连接池中的最小空闲连接 默认 0
spring.redis.lettuce.pool.min-idle=0


3、 Cache核心注解


spring-boot-starter-cache 是 Spring Boot 体系内提供使⽤ Spring Cache的Starter 包。其中最核⼼的三个注解:@Cacheable、@CacheEvict、@CachePut。

3.1、@Cacheable

@Cacheable⽤来声明⽅法是可缓存的,将结果存储到缓存中以便后续使⽤相同参数调⽤时不需执⾏实际的⽅法,直接从缓存中取值。@Cacheable 可以标记在⼀个⽅法上,也可以标记在⼀个类上。当标记在⼀个⽅法上时表示该⽅法是⽀持缓存的,当标记在⼀个类上时则表示该类所有的⽅法都是⽀持缓存的。

例如:

@RequestMapping("/hello")
@Cacheable(value="helloCache")
public String hello(String name) {
 System.out.println("没有⾛缓存!");
 return "hello "+name;
}

@Cacheable ⽀持如下⼏个参数。

  • value:缓存的名称。
  • key:缓存的 key,可以为空,如果指定要按照 SpEL 表达式编写;如果不指定,则缺省按照⽅法的所有参数进⾏组合。
  • condition:触发条件,只有满⾜条件的情况才会加⼊缓存,默认为空,既表示全部都加⼊缓存,⽀持SpEL。

把上⾯的⽅法稍微更改:

@RequestMapping("/condition")
@Cacheable(value="condition",condition="#name.length() <= 4")
public String condition(String name) {
 System.out.println("没有⾛缓存!");
 return "hello "+name;
}


3.2、@CachePut

项⽬运⾏中会对数据库的信息进⾏更新,如果仍然使⽤ @Cacheable 就会导致数据库的信息和缓存的信息不⼀致。在以往的项⽬中,⼀般更新完数据库后,再⼿动删除掉 Redis 中对应的缓存,以保证数据的⼀致性。Spring 提供了另外的⼀种解决⽅案,可以以优雅的⽅式去更新缓存。

与 @Cacheable 不同的是使⽤ @CachePut 标注的⽅法在执⾏前,不会去检查缓存中是否存在之前执⾏过的结果,⽽是每次都会执⾏该⽅法,并将执⾏结果以键值对的形式存⼊指定的缓存中。

@CachePut 配置⽅法:

  • value 缓存的名称。
  • key 缓存的 key,可以为空,如果指定要按照 SpEL 表达式编写,如果不指定,则缺省按照⽅法的所有参数进⾏组合。
  • condition 缓存的条件,可以为空,使⽤ SpEL 编写,返回 true 或者 false,只有为 true 才进⾏缓存。


3.3、@CacheEvict

@CacheEvict 是⽤来标注在需要清除缓存元素的⽅法或类上的,当标记在⼀个类上时表示其中所有的⽅法的执⾏都会触发缓存的清除操作。@CacheEvict 可以指定的属性有 value、key、condition、allEntries 和beforeInvocation,其中 value、key 和 condition 的语义与 @Cacheable 对应的属性类似。即 value 表示清除操作是发⽣在哪些 Cache 上的(对应 Cache 的名称);key 表示需要清除的是哪个 key,如未指定则会使⽤默认策略⽣成的 key;condition 表示清除操作发⽣的条件。


3.4、总结

  • @Cacheable 作⽤和配置⽅法

主要针对⽅法配置,能够根据⽅法的请求参数对其结果进⾏缓存:

主要参数 解 释 举例
value 缓存的名称,在 spring 配置⽂件中定义,必须指定⾄少⼀个 如 @Cacheable(value="mycache")或者 @Cacheable(value={"cache1","cache2"}
key 缓存的 key,可以为空,如果指定要按照 SpEL表达式编写,如果不指定,则缺省按照⽅法的所有参数进⾏组合 如@Cacheable(value="testcache",key="#userName")
condition 缓存的条件,可以为空,使⽤ SpEL 编写,返回true 或者 false,只有为 true 才进⾏缓存 如@Cacheable(value="testcache",condition="#userName.length()>2")


  • @CachePut 作⽤和配置⽅法

@CachePut 的作⽤是主要针对⽅法配置,能够根据⽅法的请求参数对其结果进⾏缓存,和 @Cacheable 不同的是,它每次都会触发真实⽅法的调⽤。

主要参数 解释 举例
value 缓存的名称,在 spring 配置⽂件中定义,必须指定⾄少⼀个 如@Cacheable(value="mycache")或者 @Cacheable(value={"cache1","cache2"}
key 缓存的 key,可以为空,如果指定要按照 SpEL表达式编写,如果不指定,则缺省按照⽅法的所有参数进⾏组合 如@Cacheable(value="testcache",key="#userName")
condition 缓存的条件,可以为空,使⽤ SpEL 编写,返回true 或者 false,只有为 true 才进⾏缓存 如@Cacheable(value="testcache",condition="#userName.length()>2")


  • @CacheEvict 作⽤和配置⽅法

主要针对⽅法配置,能够根据⼀定的条件对缓存进⾏清空。

主要参数 解释 举例
value 缓存的名称,在 spring 配置⽂件中定义,必须指定⾄少⼀个 如 @CachEvict(value="mycache")或者 @CachEvict(value={"cache1","cache2"}
key 缓存的 key,可以为空,如果指定要按照SpEL 表达式编写,如果不指定,则缺省按照⽅法的所有参数进⾏组合 如@CachEvict(value="testcache",key="#userName")
condition 缓存的条件,可以为空,使⽤ SpEL 编写,返回 true 或者 false,只有为 true 才清空缓存 如@CachEvict(value="testcache",condition="#userName.length()>2")
allEntries 是否清空所有缓存内容,缺省为 false,如果指定为 true,则⽅法调⽤后将⽴即清空所有缓存 如@CachEvict(value="testcache",allEntries=true)
beforeInvocation 是否在⽅法执⾏前就清空,缺省为 false,如果指定为 true,则在⽅法还没有执⾏的时候就清空缓存,缺省情况下,如果⽅法执⾏抛出异常,则不会清空缓存 如@CachEvict(value="testcache",beforeInvocation=true)


4、Cache具体使用

4.1、实体类

定义一个User类,模拟对象存储:

public class User implements Serializable {
    private static final long serialVersionUID = 8655851615465363473L;
    private Long id;
    private String username;
    private String password;
    
    //省略getter、setter
}       


4.2、服务层


  • 接口:
public interface UserService {

    /**
     * 删除
     *
     * @param user 用户对象
     * @return 操作结果
     */
    User saveOrUpdate(User user);

    /**
     * 添加
     *
     * @param id key值
     * @return 返回结果
     */
    User get(Long id);

    /**
     * 删除
     *
     * @param id key值
     */
    void delete(Long id);
}


  • 实现类:

实现类里用到了最核心的三个注解:@Cacheable、@CachePut、@CacheEvict

@Service
public class UserServiceImpl implements UserService {
    private static final Map<Long, User> DATABASES = new HashMap<>();

    static {
        DATABASES.put(1L, new User(1L, "u1", "p1"));
        DATABASES.put(2L, new User(2L, "u2", "p2"));
        DATABASES.put(3L, new User(3L, "u3", "p3"));
    }


    private static final Logger log = LoggerFactory.getLogger(UserServiceImpl.class);

    @Cacheable(value = "user", key = "#id")
    @Override
    public User get(Long id) {
        // TODO 假设它是从数据库读取出来的
        log.info("进入 get 方法");
        return DATABASES.get(id);
    }

    @CachePut(value = "user", key = "#user.id")
    @Override
    public User saveOrUpdate(User user) {
        DATABASES.put(user.getId(), user);
        log.info("进入 saveOrUpdate 方法");
        return user;
    }

    @CacheEvict(value = "user", key = "#id")
    @Override
    public void delete(Long id) {
        DATABASES.remove(id);
        log.info("进入 delete 方法");
    }
}


4.4、启动类

启动类需要开启缓存配置@EnableCaching

@SpringBootApplication
@EnableCaching
public class SpringbootCacheRedisApplication {

    public static void main(String[] args) {
        SpringApplication.run(SpringbootCacheRedisApplication.class, args);
    }

}


4.5、测试

@RunWith(SpringRunner.class)
@SpringBootTest
public class CacheRedisTest {

    private static final Logger log = LoggerFactory.getLogger(CacheRedisTest.class);


    @Autowired
    private UserService userService;


    @Test
    public void get() {
        final User user = userService.saveOrUpdate(new User(5L, "u5", "p5"));
        log.info("[saveOrUpdate] - [{}]", user);
        final User user1 = userService.get(5L);
        log.info("[get] - [{}]", user1);
        userService.delete(5L);
    }
}

运行结果:

在这里插入图片描述可以看到增删改查中,查询是没有日志输出的,因为它直接从缓存中获取的数据,而添加、修改、删除都是会进入方法内执行具体的业务代码,然后通过切面去删除掉Redis中的缓存数据。



参考:

【1】:《精通 Spring Boot 42 讲》
【2】:一起来学SpringBoot | 第十篇:使用Spring Cache集成Redis
【3】:《Spring Boot Vue全栈开发实战》
【4】:Spring Cache + 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
目录
相关文章
|
17天前
|
存储 缓存 NoSQL
数据的存储--Redis缓存存储(一)
数据的存储--Redis缓存存储(一)
53 1
|
17天前
|
存储 缓存 NoSQL
数据的存储--Redis缓存存储(二)
数据的存储--Redis缓存存储(二)
33 2
数据的存储--Redis缓存存储(二)
|
13天前
|
消息中间件 缓存 NoSQL
Redis 是一个高性能的键值对存储系统,常用于缓存、消息队列和会话管理等场景。
【10月更文挑战第4天】Redis 是一个高性能的键值对存储系统,常用于缓存、消息队列和会话管理等场景。随着数据增长,有时需要将 Redis 数据导出以进行分析、备份或迁移。本文详细介绍几种导出方法:1)使用 Redis 命令与重定向;2)利用 Redis 的 RDB 和 AOF 持久化功能;3)借助第三方工具如 `redis-dump`。每种方法均附有示例代码,帮助你轻松完成数据导出任务。无论数据量大小,总有一款适合你。
50 6
|
17天前
|
缓存 NoSQL Java
springboot的缓存和redis缓存,入门级别教程
本文介绍了Spring Boot中的缓存机制,包括使用默认的JVM缓存和集成Redis缓存,以及如何配置和使用缓存来提高应用程序性能。
55 1
springboot的缓存和redis缓存,入门级别教程
|
9天前
|
前端开发 Java 程序员
springboot 学习十五:Spring Boot 优雅的集成Swagger2、Knife4j
这篇文章是关于如何在Spring Boot项目中集成Swagger2和Knife4j来生成和美化API接口文档的详细教程。
25 1
|
14天前
|
存储 缓存 NoSQL
大数据-38 Redis 高并发下的分布式缓存 Redis简介 缓存场景 读写模式 旁路模式 穿透模式 缓存模式 基本概念等
大数据-38 Redis 高并发下的分布式缓存 Redis简介 缓存场景 读写模式 旁路模式 穿透模式 缓存模式 基本概念等
36 4
|
14天前
|
缓存 NoSQL Ubuntu
大数据-39 Redis 高并发分布式缓存 Ubuntu源码编译安装 云服务器 启动并测试 redis-server redis-cli
大数据-39 Redis 高并发分布式缓存 Ubuntu源码编译安装 云服务器 启动并测试 redis-server redis-cli
41 3
|
14天前
|
消息中间件 缓存 NoSQL
大数据-49 Redis 缓存问题中 穿透、雪崩、击穿、数据不一致、HotKey、BigKey
大数据-49 Redis 缓存问题中 穿透、雪崩、击穿、数据不一致、HotKey、BigKey
33 2
|
14天前
|
缓存 分布式计算 NoSQL
大数据-47 Redis 缓存过期 淘汰删除策略 LRU LFU 基础概念
大数据-47 Redis 缓存过期 淘汰删除策略 LRU LFU 基础概念
35 2
|
9天前
|
Java Spring
springboot 学习十一:Spring Boot 优雅的集成 Lombok
这篇文章是关于如何在Spring Boot项目中集成Lombok,以简化JavaBean的编写,避免冗余代码,并提供了相关的配置步骤和常用注解的介绍。
42 0