【Spring Boot 3】【Redis】基本数据类型操作

news2024/9/24 11:32:00

【Spring Boot 3】【Redis】基本数据类型操作

  • 背景
  • 介绍
  • 开发环境
  • 开发步骤及源码
  • 工程目录结构

背景

软件开发是一门实践性科学,对大多数人来说,学习一种新技术不是一开始就去深究其原理,而是先从做出一个可工作的DEMO入手。但在我个人学习和工作经历中,每次学习新技术总是要花费或多或少的时间、检索不止一篇资料才能得出一个可工作的DEMO,这占用了我大量的时间精力。因此本文旨在通过一篇文章即能还原出可工作的、甚至可用于生产的DEMO,期望初学者能尽快地迈过0到1的这一步骤,并在此基础上不断深化对相关知识的理解。
为达以上目的,本文会将开发环境、工程目录结构、开发步骤及源码尽量全面地展现出来,文字描述能简则简,能用代码注释的绝不在正文中再啰嗦一遍,正文仅对必要且关键的信息做重点描述。

介绍

本文介绍开发Spring Boot应用时借助Spring Data Redis实现对Redis五种基本数据(字符串string、哈希hash、列表list、集合set、有序集合zset)类型的操作。

开发环境

分类名称版本
操作系统WindowsWindows 11
JDKOracle JDK21.0.1
IDEIntelliJ IDEA2023.2.4
构建工具Apache Maven3.9.3
缓存Redis7.2

开发步骤及源码

1> 创建Maven工程,添加依赖。

    <properties>
        <spring-boot.version>3.2.1</spring-boot.version>
    </properties>

    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-redis</artifactId>
            <version>${spring-boot.version}</version>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <version>${spring-boot.version}</version>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>com.fasterxml.jackson.core</groupId>
            <artifactId>jackson-databind</artifactId>
            <version>2.15.3</version>
        </dependency>
    </dependencies>

2> 添加应用配置(src/main/resources/application.yml)。

spring:
  data:
    redis:
      # 连接地址
      host: 127.0.0.1
      # 端口
      port: 6379
      # Redis数据库索引,默认为 0
      database: 0
      # 用户名(可选)
      # username:
      # 密码(可选)
      # password:

3> 定义SpringBoot应用启动类。

package com.jiyongliang.springboot;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

@SpringBootApplication
public class SpringBoot3RedisDataApplication {

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

4> 字符串(string)

package com.jiyongliang.springboot;

import org.assertj.core.api.Assertions;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.data.redis.core.RedisTemplate;

@SpringBootTest
class RedisStringTests {

    @Autowired
    RedisTemplate<String, Object> redisTemplate;

    String key = "string-key";

    @AfterEach
    void afterEach() {
        redisTemplate.delete(key);
    }

    @Test
    void testString() {
        // 添加字符串缓存数据
        redisTemplate.opsForValue().set(key, "string data");
        // 获取字符串缓存数据
        String cachedString = (String) redisTemplate.opsForValue().get(key);
        Assertions.assertThat(cachedString)
                .isNotNull()
                .isEqualTo("string data");
    }
}

5> 哈希(hash)

package com.jiyongliang.springboot;

import org.assertj.core.api.Assertions;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.data.redis.core.RedisTemplate;

import java.util.HashMap;
import java.util.Map;

@SpringBootTest
class RedisHashTests {

    @Autowired
    RedisTemplate<String, Object> redisTemplate;

    String key = "hash-single-key";

    @BeforeEach
    void beforeEach() {
        redisTemplate.delete(key);
    }

    @Test
    void testHash() {
        // 添加单个Hash缓存数据
        redisTemplate.opsForHash().put(key, "hash key", "hash value");
        // 获取单个Hash缓存数据
        String cachedHash = (String) redisTemplate.opsForHash().get(key, "hash key");
        Assertions.assertThat(cachedHash).isEqualTo("hash value");
        redisTemplate.delete(key);
        // 添加map缓存数据
        Map<String, String> map = new HashMap<>();
        map.put("map-key-1", "map value 1");
        map.put("map-key-2", "map value 2");
        map.put("map-key-3", "map value 3");
        redisTemplate.opsForHash().putAll(key, map);
        // 获取map缓存数据
        Map<Object, Object> cachedHashMap = redisTemplate.opsForHash().entries(key);
        Assertions.assertThat(cachedHashMap)
                .isNotNull()
                .containsEntry("map-key-1", "map value 1")
                .containsEntry("map-key-2", "map value 2")
                .containsEntry("map-key-3", "map value 3");
    }
}

6> 列表(list)

package com.jiyongliang.springboot;

import org.assertj.core.api.Assertions;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.data.redis.core.RedisTemplate;

import java.util.List;

@SpringBootTest
class RedisListTests {

    @Autowired
    RedisTemplate<String, Object> redisTemplate;

    String key = "list-key";

    @BeforeEach
    void beforeEach() {
        redisTemplate.delete(key);
    }

    @Test
    void testList() {
        // 添加List缓存数据
        redisTemplate.opsForList().leftPush(key, "list value 3");
        redisTemplate.opsForList().leftPush(key, "list value 2");
        redisTemplate.opsForList().leftPush(key, "list value 1");
        redisTemplate.opsForList().rightPush(key, "list value 4");
        redisTemplate.opsForList().rightPush(key, "list value 5");
        // 获取全部List缓存数据
        List<Object> cachedList = redisTemplate.opsForList().range(key, 0, -1);
        Assertions.assertThat(cachedList)
                .isNotNull()
                .isNotEmpty()
                .hasToString("[list value 1, list value 2, list value 3, list value 4, list value 5]");
        // 获取指定下标数据
        String listValue = (String) redisTemplate.opsForList().index(key, 2);
        Assertions.assertThat(listValue).isEqualTo("list value 3");
        listValue = (String) redisTemplate.opsForList().index(key, 5);
        Assertions.assertThat(listValue).isNull();
        // 从左边开始取数据
        listValue = (String) redisTemplate.opsForList().leftPop(key);
        Assertions.assertThat(listValue).isEqualTo("list value 1");
        // 从右边开始取数据
        listValue = (String) redisTemplate.opsForList().rightPop(key);
        Assertions.assertThat(listValue).isEqualTo("list value 5");
        // 获取list长度
        Long length = redisTemplate.opsForList().size(key);
        Assertions.assertThat(length).isNotNull().isEqualTo(3);
        Assertions.assertThat(redisTemplate.opsForList().range(key, 0, -1))
                .isNotNull()
                .isNotEmpty()
                .hasToString("[list value 2, list value 3, list value 4]");
    }
}

7> 集合(set)

package com.jiyongliang.springboot;

import org.assertj.core.api.Assertions;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.data.redis.core.RedisTemplate;

import java.util.Arrays;
import java.util.Set;
import java.util.stream.Collectors;

@SpringBootTest
class RedisSetTests {

    @Autowired
    RedisTemplate<String, Object> redisTemplate;

    String key1 = "set-key-1";

    String key2 = "set-key-2";

    @BeforeEach
    void beforeEach() {
        redisTemplate.delete(key1);
        redisTemplate.delete(key2);
    }

    @Test
    void testSet() {
        // 添加Set缓存数据
        String[] setData = new String[]{"A", "B", "C", "D", "D", "C", "D", "E", "F", "F", "G"};
        Long addCount = redisTemplate.opsForSet().add(key1, setData);
        Set<String> expected = Arrays.stream(setData).collect(Collectors.toSet());
        Assertions.assertThat(addCount).isNotNull().isEqualTo(expected.size());
        // 获取Set缓存数据
        Set<Object> cachedSet = redisTemplate.opsForSet().members(key1);
        Assertions.assertThat(cachedSet)
                .isNotNull()
                .hasSameSizeAs(expected)
                .containsAll(expected);
        // 判断是否在Set缓存数据中
        Assertions.assertThat(redisTemplate.opsForSet().isMember(key1, "F")).isTrue();
        Assertions.assertThat(redisTemplate.opsForSet().isMember(key1, "X")).isFalse();
        // 返回缓存Set的并集
        String[] setTempData = new String[]{"A", "X", "E", "Y", "G", "Z"};
        redisTemplate.opsForSet().add(key2, setTempData);
        Set<Object> unionSet = redisTemplate.opsForSet().union(key1, key2);
        Assertions.assertThat(unionSet)
                .isNotNull()
                .hasSize(expected.size() + 3)
                .containsAll(expected)
                .containsAll(Set.of("X", "Y", "Z"));
        // 返回缓存Set的交集
        Set<Object> intersectSet = redisTemplate.opsForSet().intersect(key1, key2);
        Assertions.assertThat(intersectSet)
                .isNotNull()
                .hasSize(3)
                .containsAll(Set.of("A", "E", "G"));
        // 返回缓存的set-key-1中存在但set-key-2中不存在的数据
        Set<Object> differenceSet = redisTemplate.opsForSet().difference(key1, key2);
        Assertions.assertThat(differenceSet)
                .isNotNull()
                .hasSize(expected.size() - 3)
                .containsAll(Set.of("B", "C", "D", "F"));
    }
}

8> 有序集合(zset)

package com.jiyongliang.springboot;

import org.assertj.core.api.Assertions;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.data.redis.core.RedisTemplate;

import java.util.Set;

@SpringBootTest
class RedisZSetTests {

    @Autowired
    RedisTemplate<String, Object> redisTemplate;

    String key = "zset-key";

    @BeforeEach
    void beforeEach() {
        redisTemplate.delete(key);
    }

    @Test
    void testZSet() {
        // 添加ZSet缓存数据
        redisTemplate.opsForZSet().add(key, "X", 1);
        redisTemplate.opsForZSet().add(key, "Y", 2);
        redisTemplate.opsForZSet().add(key, "Z", 3);
        // 值相同的情况下,权重会被覆盖
        redisTemplate.opsForZSet().add(key, "X", 1);
        redisTemplate.opsForZSet().add(key, "Y", 3);
        redisTemplate.opsForZSet().add(key, "Z", 5);
        // 获取ZSet缓存数据
        Set<Object> cachedZSet = redisTemplate.opsForZSet().range(key, 0, -1);
        Assertions.assertThat(cachedZSet)
                .isNotNull()
                .hasSize(3)
                .containsAll(Set.of("X", "Y", "Z"));
        // 获取值对应的权重
        Double score = redisTemplate.opsForZSet().score(key, "Y");
        Assertions.assertThat(score).isNotNull().isEqualTo(3);
        // 获取值对应的排名(从0开始)
        Long rank = redisTemplate.opsForZSet().rank(key, "Y");
        Assertions.assertThat(rank).isNotNull().isEqualTo(1);
        // 根据score范围获取值
        Set<Object> rangedZSet = redisTemplate.opsForZSet().rangeByScore(key, 1, 4);
        Assertions.assertThat(rangedZSet)
                .isNotNull()
                .hasSize(2)
                .containsAll(Set.of("X", "Y"));
    }
}

9> 数据过期

package com.jiyongliang.springboot;

import org.assertj.core.api.Assertions;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.data.redis.core.RedisTemplate;

import java.util.concurrent.TimeUnit;

@SpringBootTest
class RedisExpireTests {

    @Autowired
    RedisTemplate<String, Object> redisTemplate;

    String key = "expire-key";

    @BeforeEach
    void beforeEach() {
        redisTemplate.delete(key);
    }

    @Test
    void testExpire() throws InterruptedException {
        redisTemplate.opsForValue().set(key, "expire data");
        Assertions.assertThat(redisTemplate.opsForValue().get(key))
                .isNotNull()
                .isEqualTo("expire data");
        redisTemplate.opsForValue().getOperations().expire(key, 3, TimeUnit.SECONDS);
        TimeUnit.SECONDS.sleep(3);
        Assertions.assertThat(redisTemplate.opsForValue().get(key)).isNull();
    }
}

10> 单元测试结果
单元测试结果

工程目录结构

工程目录结构

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

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

相关文章

priority_queue的使用与模拟实现(容器适配器+stack与queue的模拟实现源码)

priority_queue的使用与模拟实现 引言&#xff08;容器适配器&#xff09;priority_queue的介绍与使用priority_queue介绍接口使用默认成员函数 size与emptytoppush与pop priority_queue的模拟实现构造函数size与emptytoppush与pop向上调整建堆与向下调整建堆向上调整建堆向下调…

UE5 蓝图编辑美化学习

虚幻引擎中干净整洁蓝图的15个提示_哔哩哔哩_bilibili 1.双击线段成节点。 好用&#xff0c;爱用 2.用序列节点 好用&#xff0c;爱用 3.用枚举。 好用&#xff0c;能避免一些的拼写错误 4.对齐节点 两点一水平线 5.节点上下贴节点 &#xff08;以前不懂&#xff0c;现在经常…

【AJAX框架】AJAX入门与axios的使用

文章目录 前言一、AJAX是干什么的&#xff1f;二、AJAX的安装2.1 CDN引入2.2 npm安装 三、基础使用3.1 CDN方式3.2 node方式 总结 前言 在现代Web开发中&#xff0c;异步JavaScript和XML&#xff08;AJAX&#xff09;已经成为不可或缺的技术之一。AJAX使得网页能够在不刷新整个…

SQL注入实战操作

一&#xff1a;SQl注入分类 按照注入的网页功能类型分类&#xff1a; 1、登入注入&#xff1a;表单&#xff0c;如登入表单&#xff0c;注册表单 2、cms注入&#xff1a;CMS逻辑:index.php首页展示内容&#xff0c;具有文章列表(链接具有文章id)、articles.php文 章详细页&a…

NX二次开发封装自己的函数及如何导入工程

目录 一、概述 二、函数封装 三、函数引用 四、案例——在NX中运行后输出“测试”两字 一、概述 随着对NX二次开发的学习&#xff0c;我们在各种项目里面会积累很多函数&#xff0c;对于一些经常用到的函数&#xff0c;我们可以考虑将其封装为类库&#xff0c;以后在开发其…

从请购到结算,轻松搞定!云迈ERP系统助力企业采购管理全流程!

​在企业的运营过程中&#xff0c;采购管理是至关重要的环节之一。为了确保采购流程的顺畅和高效&#xff0c;许多企业选择引入ERP&#xff08;企业资源规划&#xff09;系统来进行采购管理。那么erp系统中的采购管理都有哪些功能呢&#xff1f; 云迈erp系统中的采购管理模块&a…

虚拟机下载docker

一&#xff0c;Docker简介 百科说&#xff1a;Docker 是一个开源的应用容器引擎&#xff0c;让开发者可以打包他们的应用以及依赖包到一个可移植的容器中&#xff0c;然后发布到任何流行的Linux机器上&#xff0c;也可以实现虚拟化&#xff0c;容器是完全使用沙箱机制&#xff…

大数据导论(2)---大数据与云计算、物联网、人工智能

文章目录 1. 云计算1.1 云计算概念1.2 云计算的服务模式和类型1.3 云计算的数据中心与应用 2. 物联网2.1 物联网的概念和关键技术2.2 物联网的应用和产业2.3 大数据与云计算、物联网的关系 1. 云计算 1.1 云计算概念 1. 首先从商业角度给云计算下一个定义&#xff1a;通过网络…

第二次作业+第三次作业

第二次作业第三次作业 第二次作业 题目&#xff1a; 网站需求&#xff1a; ​ 1.基于域名[www.openlab.com](http://www.openlab.com)可以访问网站内容为 welcome to openlab!!! 2.给该公司创建三个子界面分别显示学生信息&#xff0c;教学资料和缴费网站&#xff0c;基于[ww…

Oracle架构_数据库底层原理、机制 (授人以渔)

目录 系统全局区SGA 高速缓存缓冲区(数据库缓冲区) 日志缓冲区 共享池 其他结构 用户连接进程 用户进程User Process Server Process服务进程 程序全局区PGA Oracle的connect连接和session会话与User Process紧密相关 后台进程 数据库写入进程(DBWn) 检查点(CKPT)…

php isset和array_key_exists区别

在PHP中&#xff0c;可以使用array_key_exists函数或者isset函数来判断一个字典&#xff08;关联数组&#xff09;中是否存在某个下标。 使用 array_key_exists 函数: $myArray array("key1" > "value1", "key2" > "value2",…

PyTorch视觉工具箱:图像变换与上采样技术详解(1)

目录 Pytorch中Vision functions详解 pixel_shuffle 用途 用法 使用技巧 注意事项 参数 数学理论公式 示例代码及输出 pixel_unshuffle 用途 用法 使用技巧 注意事项 参数 数学理论公式 示例代码及输出 pad 用途 用法 使用技巧 注意事项 参数 示例代码…

Verilog基础:强度建模(二)

相关阅读 Verilog基础https://blog.csdn.net/weixin_45791458/category_12263729.html?spm1001.2014.3001.5482 三、拥有单个强度和确定值的net型信号的线与组合&#xff08;线网多驱动&#xff09; 首先来说明一下什么叫信号拥有单个强度和确定值&#xff0c;其实如果一个ne…

使用KTO进行更好、更便宜、更快速的LLM对齐

KTO全称为Kahneman-Tversky Optimisation&#xff0c;这种对齐方法使在我们的数据上对大型语言模型&#xff08;LLM&#xff09;进行对齐变得前所未有地容易和便宜&#xff0c;而且不会损害性能。大型语言模型的成功在很大程度上得益于与人类反馈的对齐。如果ChatGPT曾经拒绝回…

禅道使用教程

禅道的使用 一.禅道的使用1.添加部门和批量添加用户2.以产品经理的身份登录进行使用和操作2.1创建产品2.2创建模块2.3添加产品计划2.4添加产品需求2.5创建项目2.6设置团队 3.项目经理使用禅道3.1关联需求3.2批量分解,给人员分配任务3.3假设项目完成开发,项目经理创建版本 4.测试…

《数字图像处理-OpenCV/Python》连载:傅里叶变换与频域滤波

《数字图像处理-OpenCV/Python》连载&#xff1a;空间滤波之高斯滤波器 本书京东 优惠购书链接 https://item.jd.com/14098452.html 本书CSDN 独家连载专栏 https://blog.csdn.net/youcans/category_12418787.html 第 11 章 傅里叶变换与频域滤波 空间图像滤波是图像与滤波器核…

根据基因名批量查找它的Uniprot编号

背景&#xff1a; 前几天老师交给我一个任务&#xff0c;给我一个基因列表&#xff0c;让我查找它们所编码的蛋白质的蛋白质序列。我上了一下uniprot数据库&#xff0c;发现这个任务可以分成两步&#xff1a; 找到这个基因在Uniprot数据库中所对应的蛋白质编码根据蛋白质编码…

街机模拟游戏逆向工程(HACKROM)教程:[12]68K汇编-程序流控制

在之前的文章中&#xff0c;我们测试过一些简短的一小段程序&#xff0c;这些程序都有一个共同的程序运行流程&#xff0c;就是一句一句地向下执行&#xff0c;比如&#xff1a; movea.l #$325, a0 * ↓move.b #$01, (a0) * ↓move.b #$02, $01(a…

【软件测试常见Bug清单】

软件测试中&#xff0c;bug的类型有很多种&#xff0c;比如&#xff1a;代码错误、界面优化、设计缺陷、需求补充和用户体验等&#xff1b; 一般情况下&#xff0c;需求补充和设计缺陷比较好区分&#xff0c;但是代码错误、界面优化和用户体验区分不是很明显&#xff1b; 下面…

主动轮廓——计算机视觉中的图像分割方法

​ 一、说明 简单来说&#xff0c;计算机视觉就是为计算机提供类似人类的视觉。作为人类&#xff0c;我们很容易识别任何物体。我们可以很容易地识别山丘、树木、土地、动物等&#xff0c;但计算机没有眼睛&#xff0c;也没有大脑&#xff0c;因此它很难识别任何图像。计算机只…