SpringBoot 实战 (二十)| 整合 Redis

本文涉及的产品
RDS MySQL Serverless 基础系列,0.5-2RCU 50GB
Redis 开源版,标准版 2GB
推荐场景:
搭建游戏排行榜
RDS MySQL Serverless 高可用系列,价值2615元额度,1个月
简介: SpringBoot 实战 (二十)| 整合 Redis

Redis 简介


Redis 是一个开源的,基于内存的键值数据存储,用作数据库,缓存和消息代理。在实现方面,Key-Value 存储代表 NoSQL 空间中最大和最老的成员之一。Redis 支持数据结构,如字符串,散列,列表,集和带范围查询的有序集。

在 spring data redis 的框架,可以很容易地编写,通过提供一个抽象的数据存储使用 Redis 的键值存储的 Spring 应用程序。

非关系型数据库,基于内存,存取数据的速度不是关系型数据库所能比拟的

redis 是键值对 (key-value) 的数据库


数据类型


1. 字符串类型 string

2. 散列类型 hash

3. 列表类型 list

4. 集合类型 set

5. 有序集合类型 zset


其中,因为SpringBoot 约定大于配置的特点,只要我们加入了 spring-data-redis 依赖包并配置 Redis 数据库,SpringBoot 就会帮我们自动配置一个 RedisTemplate ,利用它我们就可以按照以下方式操作对应的数据类型,在下面实战中我将会对这五种数据进行操作。


1. redisTemplate.opsForValue(); //操作字符串

2. redisTemplate.opsForHash(); //操作hash

3. redisTemplate.opsForList(); //操作list

4. redisTemplate.opsForSet(); //操作set

5. redisTemplate.opsForZSet(); //操作有序set


开发环境


1. SpringBoot 2.1.6 RELEASE

2. Spring-data-redis 2.1.9 RELEASE

3. Redis 3.2

4. IDEA

5. JDK8

6. mysql


关于如何安装 Redis 这里不再赘述,请自行搜索引擎搜索解决。


pom 依赖


<dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-jpa</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-redis</artifactId>
        </dependency>
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <scope>runtime</scope>
        </dependency>
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <optional>true</optional>
        </dependency>
        <!-- https://mvnrepository.com/artifact/com.alibaba/fastjson -->
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>fastjson</artifactId>
            <version>1.2.58</version>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
</dependencies>


配置文件


spring:
  datasource:
    driver-class-name: com.mysql.cj.jdbc.Driver
    url: jdbc:mysql://127.0.0.1:3306/test?useUnicode=true&characterEncoding=utf8&serverTimezone=UTC&useSSL=true
    username: root
    password: 123456
  jpa:
    hibernate:
      ddl-auto: update   #ddl-auto:设为 create 表示每次都重新建表
    show-sql: true
  redis:
    host: localhost
    port: 6379
    # Redis数据库索引(默认为0)
    database: 1
    jedis:
      pool:
        #连接池最大连接数
        max-active: 8
        #最小空闲连接
        min-idle: 0
        #最大阻塞等待时间,负值表示没有限制
        max-wait: -1ms
        #最大空闲连接
        max-idle: 8
    #连接超时时间(毫秒)
    timeout: 20ms
    # 无密码可不写
    # password:


为什么乱码?


/**
     * 添加字符串
     */
    @Test
    public void setString(){
        redisTemplate.opsForValue().set(USERKEY,"nasus");
        redisTemplate.opsForValue().set(AGEKEY,24);
        redisTemplate.opsForValue().set(CITYKEY,"清远");
    }


首先是添加字符串类型的数据。它的运行结果如下:


640.jpg


如何解决乱码


我们可以看到插入的数据是乱码的,这是因为 SpringBoot 自动配置的这个 RedisTemplate 是没有设置数据读取时的 key 及 value 的序列化方式的。所以,我们要写一个自己的 RedisTemplate 并设置 key 及 value 的序列化方式才可以正常操作 Redis。如下:


@Configuration
public class RedisConfig {
    private final RedisTemplate redisTemplate;
    @Autowired
    public RedisConfig(RedisTemplate redisTemplate) {
        this.redisTemplate = redisTemplate;
    }
    @Bean
    @SuppressWarnings("unchecked")
    public RedisTemplate<String, Object> redisTemplate() {
        RedisSerializer<String> stringSerializer = new StringRedisSerializer();
        //RedisSerializer<Object> jsonString = new GenericToStringSerializer<>(Object.class);
        RedisSerializer<Object> jsonString = new FastJsonRedisSerializer<>(Object.class);
        // String 的 key 和 hash 的 key 都采用 String 的序列化方式
        redisTemplate.setKeySerializer(stringSerializer);
        redisTemplate.setHashKeySerializer(stringSerializer);
        // value 都采用 fastjson 的序列化方式
        redisTemplate.setValueSerializer(jsonString);
        redisTemplate.setHashValueSerializer(jsonString);
        return redisTemplate;
    }
}


这时,再次运行上面的单元测试,结果就正常了。


640.jpg


操作 List


/**
     * 添加、获取LIST
     */
    @Test
    public void setList(){
        List<Student> students = studentService.findStudentList();
        log.info("students size = {}", students.size());
        //循环向 studentList 左添加值
        students.forEach(value->redisTemplate.opsForList().leftPush(LISTKEY,value));
        //向 studentList 右添加值
        Student student = new Student();
        student.setId(10);
        student.setAge(24);
        student.setName("rightPush");
        redisTemplate.opsForList().rightPush(LISTKEY,student);
        // 获取值
        log.info("studentList->{}",redisTemplate.opsForList().range(LISTKEY,0,10));
    }


这里需要说一下,leftpush 和 rightpush 的区别,前者是在 key 对应 list 的头部添加元素,也就是我们常说的后来居上,List下标最大的元素在这个 list 里面处于第一位;而后者则是 在 key 对应 list 的尾部添加元素,刚好和前者相反。


获取值,代码这里获取的是 0 到 10 行的数据,控制台打印结果:


[{"name":"优秀","id":9,"age":22}, {"name":"冯某华","id":8,"age":25}, {"name":"蓝某城","id":7,"age":25}, {"name":"优秀","id":6,"age":22}, {"name":"冯某华","id":5,"age":25}, {"name":"蓝某城","id":4,"age":25}, {"name":"冯某华","id":3,"age":25}, {"name":"蓝某城","id":2,"age":25}, {"name":"废人","id":1,"age":22}, {"name":"rightPush","id":10,"age":24}]


添加 List 结果:


640.png


这里注意 1 到 9 行的 id 值刚好是相反的,而正常情况下,我从 mysql 数据中查出来的值是这样的:


640.png

因此,验证了 leftpush 和 rightpush 的区别。


操作 set


/**
     * 添加和获取Set
     */
    @Test
    public void setAndGetSet(){
        List<String> usernameList = new ArrayList<>();
        usernameList.add("nasus");
        usernameList.add("nasus");
        usernameList.add("一个优秀的废人");
        //循环向添加值
        usernameList.forEach(value->redisTemplate.opsForSet().add(SETKEY,value));
        log.info("取出usernameSet->{}",redisTemplate.opsForSet().members(SETKEY));
    }
    /**
     * 删除 Set
     */
    @Test
    public void delSet(){
        redisTemplate.opsForSet().remove(SETKEY,"nasus");
    }


Redis 的 set 数据结构跟 java 的 hashset 数据结构一样,也是无序且不重复。所以我代码里 add 了两个 nasus 字符串,其实只 add 了一个 nasus 。结果如下:


640.png


操作 hash


分别作了 hash 的添加、删除以及获取,代码如下:这里需要说明一下的是,hash 的 hash 有两个键可以设置,其中第一个是 redis 中的键,而第二个是具体每条数据的 hashkey。


/**
     * 添加 hash
     */
    @Test
    public void setHash(){
        List<Student> students = studentService.findStudentList();
        //添加
        for (Student student : students){
            redisTemplate.opsForHash().put(HASHKEY, student.getId().toString(), student);
        }
    }
    /**
     * 删除 hash
     */
    @Test
    public void delHash(){
        Student student = studentService.findStudentById(0);
        // 删除
        redisTemplate.opsForHash().delete(HASHKEY,JSON.toJSONString(student));
    }
    /**
     * 获取 Hash
     */
    @Test
    public void getHash(){
        List<Student> students = redisTemplate.opsForHash().values(HASHKEY);
        log.info("values = {}", students);
    }


添加 hash 操作结果:


640.png


获取 hash 操作结果:


640.jpg


源码地址


https://github.com/turoDog/Demo/tree/master/springboot_redis_demo


推荐阅读


SpringBoot | 自动配置原理


后语


如果本文对你哪怕有一丁点帮助,请帮忙点好看。你的好看是我坚持写作的动力。

相关文章
|
22天前
|
NoSQL Java 网络安全
SpringBoot启动时连接Redis报错:ERR This instance has cluster support disabled - 如何解决?
通过以上步骤一般可以解决由于配置不匹配造成的连接错误。在调试问题时,一定要确保服务端和客户端的Redis配置保持同步一致。这能够确保SpringBoot应用顺利连接到正确配置的Redis服务,无论是单机模式还是集群模式。
142 5
|
2月前
|
存储 NoSQL 前端开发
Redis专题-实战篇一-基于Session和Redis实现登录业务
本项目基于SpringBoot实现黑马点评系统,涵盖Session与Redis两种登录方案。通过验证码登录、用户信息存储、拦截器校验等流程,解决集群环境下Session不共享问题,采用Redis替代Session实现数据共享与自动续期,提升系统可扩展性与安全性。
213 3
Redis专题-实战篇一-基于Session和Redis实现登录业务
|
2月前
|
存储 缓存 NoSQL
Redis专题-实战篇二-商户查询缓存
本文介绍了缓存的基本概念、应用场景及实现方式,涵盖Redis缓存设计、缓存更新策略、缓存穿透问题及其解决方案。重点讲解了缓存空对象与布隆过滤器的使用,并通过代码示例演示了商铺查询的缓存优化实践。
165 1
Redis专题-实战篇二-商户查询缓存
|
2月前
|
NoSQL Java 调度
分布式锁与分布式锁使用 Redis 和 Spring Boot 进行调度锁(不带 ShedLock)
分布式锁是分布式系统中用于同步多节点访问共享资源的机制,防止并发操作带来的冲突。本文介绍了基于Spring Boot和Redis实现分布式锁的技术方案,涵盖锁的获取与释放、Redis配置、服务调度及多实例运行等内容,通过Docker Compose搭建环境,验证了锁的有效性与互斥特性。
178 0
分布式锁与分布式锁使用 Redis 和 Spring Boot 进行调度锁(不带 ShedLock)
|
5月前
|
缓存 监控 NoSQL
Redis 实操要点:Java 最新技术栈的实战解析
本文介绍了基于Spring Boot 3、Redis 7和Lettuce客户端的Redis高级应用实践。内容包括:1)现代Java项目集成Redis的配置方法;2)使用Redisson实现分布式可重入锁与公平锁;3)缓存模式解决方案,包括布隆过滤器防穿透和随机过期时间防雪崩;4)Redis数据结构的高级应用,如HyperLogLog统计UV和GeoHash处理地理位置。文章提供了详细的代码示例,涵盖Redis在分布式系统中的核心应用场景,特别适合需要处理高并发、分布式锁等问题的开发场景。
373 41
|
5月前
|
缓存 NoSQL 算法
高并发秒杀系统实战(Redis+Lua分布式锁防超卖与库存扣减优化)
秒杀系统面临瞬时高并发、资源竞争和数据一致性挑战。传统方案如数据库锁或应用层锁存在性能瓶颈或分布式问题,而基于Redis的分布式锁与Lua脚本原子操作成为高效解决方案。通过Redis的`SETNX`实现分布式锁,结合Lua脚本完成库存扣减,确保操作原子性并大幅提升性能(QPS从120提升至8,200)。此外,分段库存策略、多级限流及服务降级机制进一步优化系统稳定性。最佳实践包括分层防控、黄金扣减法则与容灾设计,强调根据业务特性灵活组合技术手段以应对高并发场景。
1447 7
|
5月前
|
机器学习/深度学习 存储 NoSQL
基于 Flink + Redis 的实时特征工程实战:电商场景动态分桶计数实现
本文介绍了基于 Flink 与 Redis 构建的电商场景下实时特征工程解决方案,重点实现动态分桶计数等复杂特征计算。通过流处理引擎 Flink 实时加工用户行为数据,结合 Redis 高性能存储,满足推荐系统毫秒级特征更新需求。技术架构涵盖状态管理、窗口计算、Redis 数据模型设计及特征服务集成,有效提升模型预测效果与系统吞吐能力。
518 2
|
5月前
|
机器学习/深度学习 数据采集 人机交互
springboot+redis互联网医院智能导诊系统源码,基于医疗大模型、知识图谱、人机交互方式实现
智能导诊系统基于医疗大模型、知识图谱与人机交互技术,解决患者“知症不知病”“挂错号”等问题。通过多模态交互(语音、文字、图片等)收集病情信息,结合医学知识图谱和深度推理,实现精准的科室推荐和分级诊疗引导。系统支持基于规则模板和数据模型两种开发原理:前者依赖人工设定症状-科室规则,后者通过机器学习或深度学习分析问诊数据。其特点包括快速病情收集、智能病症关联推理、最佳就医推荐、分级导流以及与院内平台联动,提升患者就诊效率和服务体验。技术架构采用 SpringBoot+Redis+MyBatis Plus+MySQL+RocketMQ,确保高效稳定运行。
380 0
|
存储 SQL 消息中间件
springboot整合redis
redis是一个支持key-value的数据库,数据全部在内存中处理,在在一定时间间隔中将数据固化到磁盘。因为是内存操作,所以速度特别快。(这里我们主要介绍redis作为缓存使用)
284 0
springboot整合redis
|
存储 缓存 NoSQL
SpringBoot整合Redis
SpringBoot整合Redis
549 0
SpringBoot整合Redis