利用Spring整合Redis

文章目录

  • 利用Spring整合Redis
    • 引入依赖
    • 配置Redis
  • 访问Redis
    • String类型数据
    • Hash类型数据
    • List类型数据
    • Set类型数据
    • SortedSort类型数据
    • 全局key
    • 简化多次访问同一个key情况代码
  • Redis中的事务
    • 核心方法execute()
    • 事务代码实例
  • 参考文献

利用Spring整合Redis

引入依赖

spring-boot-starter-data-redis

<dependency org="org.springframework.boot" name="spring-boot-starter-data-redis" rev="3.2.2"/><!-- 子pom版本: <version>xxx</version> -->
<!-- springboot或spring整合的包可以不用写子pom版本,
当前pom继承于某个父pom,父pom中声明了常用包的版本,这些版本做过测试,是兼容的,不容易出错  --><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-data-redis</artifactId></dependency>

配置Redis

  • 配置数据库参数

    # RedisProperties
    # 选择使用redis的16个库中的一个
    spring.redis.database=11
    # 访问库的ip
    spring.redis.host=localhost
    # 访问redis端口,redis默认端口为6379
    spring.redis.port=6379
    
  • 编写配置类,构造核心组件RedisTemplate

    springboot已经配置好了RedisTemplate,它在配置时将key做成了Object类型,更通用。但实际上我们在用时,key都是String类型,因此默认的配置类用起来不方便,我们最好重新做一个配置

    // 标明配置类
    @Configuration
    public class RedisConfig {// 配置RedisTemplate,以后可通过该对象访问redis// 装配返回值到容器中@Beanpublic RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory factory) {// 利用template访问redis数据库时,需要创建连接,而连接是由连接工厂创建的,故需要把连接工厂注入给template// 当我们定义一个bean时,方法上有RedisConnectionFactory这样的参数,spring容器会自动把它注入进来,即这个bean已经被容器装配了RedisTemplate<String, Object> template = new RedisTemplate<>();// 令template具有访问数据库的能力:把连接工厂注入给templatetemplate.setConnectionFactory(factory);// template配置:主要配序列化方式,用于将java语言转换为redis的key-value形式// 设置key的序列化方式// RedisSerializer类中有统一的序列化方式,我们可以直接访问// RedisSerializer.string()返回一个能够将数据序列化为字符串的序列化器template.setKeySerializer(RedisSerializer.string());// 设置value的序列化方式:// value可以是各种形式的数据,序列化为json格式,因为json数据是结构化的,恢复回来很好读取很好识别template.setValueSerializer(RedisSerializer.json());// hash比较特殊,因为hash中的数据也是以key-value形式存储,也需要序列化// 设置hash的key的序列化方式template.setHashKeySerializer(RedisSerializer.string());// 设置hash的value的序列化方式template.setHashValueSerializer(RedisSerializer.json());// 配置完后,触发一下,令template中配置生效template.afterPropertiesSet();return template;}}
    

访问Redis

利用配置好的RedisTemplate对象,对redis进行操作

哪需要访问redis,就将RedisTemplate注入到哪

@RunWith(SpringRunner.class)
@SpringBootTest
@ContextConfiguration(classes = CommunityApplication.class)
public class RedisTests {@Autowiredprivate RedisTemplate redisTemplate;.... ...}

通过redisTemplate调用opsForXXX()方法,方法的返回对象可以用来操作不同类型的数据

  • 访问String类型数据:redisTemplate.opsForValue()
  • 访问Hash类型数据:redisTemplate.opsForHash()
  • 访问List类型数据:redisTemplate.opsForList()
  • 访问Set类型数据:redisTemplate.opsForSet()
  • 访问SortedSort类型数据:redisTemplate.opsForZSet()

ops为operations的缩写

String类型数据

    // 操作redis中String类型数据@Testpublic void testStrings() {// 声明一个keyString redisKey = "test:count";// redisTemplate.opsForValue():String类型数据// 存String类型数据redisTemplate.opsForValue().set(redisKey, 1);// 取System.out.println(redisTemplate.opsForValue().get(redisKey));// 自增(redis中命令是简写,java中方法是全称)System.out.println(redisTemplate.opsForValue().increment(redisKey));// 自减System.out.println(redisTemplate.opsForValue().decrement(redisKey));}

Hash类型数据

    // 操作redis中哈希类型数据@Testpublic void testHashes() {String redisKey = "test:user";// 存redisTemplate.opsForHash().put(redisKey, "id", 1);redisTemplate.opsForHash().put(redisKey, "username", "zhangsan");// 取System.out.println(redisTemplate.opsForHash().get(redisKey, "id"));System.out.println(redisTemplate.opsForHash().get(redisKey, "username"));}

List类型数据

    // 操作redis中列表类型数据@Testpublic void testLists() {String redisKey = "test:ids";// 从左边存放redisTemplate.opsForList().leftPush(redisKey, 101);redisTemplate.opsForList().leftPush(redisKey, 102);redisTemplate.opsForList().leftPush(redisKey, 103);// 获取数据个数System.out.println(redisTemplate.opsForList().size(redisKey));// 获取索引位置处的数据System.out.println(redisTemplate.opsForList().index(redisKey, 0));// 获取某个索引范围内的数据System.out.println(redisTemplate.opsForList().range(redisKey, 0, 2));// 从左边开始取出一个数据System.out.println(redisTemplate.opsForList().leftPop(redisKey));System.out.println(redisTemplate.opsForList().leftPop(redisKey));System.out.println(redisTemplate.opsForList().leftPop(redisKey));}

Set类型数据

    // 操作redis中集合类型数据@Testpublic void testSets() {String redisKey = "test:teachers";// 给集合中存数据redisTemplate.opsForSet().add(redisKey, "刘备", "关羽", "张飞", "赵云", "诸葛亮");// 集合中元素个数System.out.println(redisTemplate.opsForSet().size(redisKey));// 随机弹出一个元素System.out.println(redisTemplate.opsForSet().pop(redisKey));// 查看集合中元素System.out.println(redisTemplate.opsForSet().members(redisKey));}

SortedSort类型数据

    // 操作redis中有序集合类型数据@Testpublic void testSortedSets() {String redisKey = "test:students";// 存数据redisTemplate.opsForZSet().add(redisKey, "唐僧", 80);redisTemplate.opsForZSet().add(redisKey, "悟空", 90);redisTemplate.opsForZSet().add(redisKey, "八戒", 50);redisTemplate.opsForZSet().add(redisKey, "沙僧", 70);redisTemplate.opsForZSet().add(redisKey, "白龙马", 60);// 有序集合中元素个数System.out.println(redisTemplate.opsForZSet().zCard(redisKey));// 查询元素的分数System.out.println(redisTemplate.opsForZSet().score(redisKey, "八戒"));// 查询指定元素正序排名(默认由小到大)System.out.println(redisTemplate.opsForZSet().rank(redisKey, "八戒"));// 查询指定元素反序排名(由大到小)System.out.println(redisTemplate.opsForZSet().reverseRank(redisKey, "八戒"));// 查询指定排名范围内数据(正,反序)System.out.println(redisTemplate.opsForZSet().range(redisKey, 0, 2));System.out.println(redisTemplate.opsForZSet().reverseRange(redisKey, 0, 2));}

全局key

// 操作redis中的key(公共命令)
@Test
public void testKeys() {// 删除keyredisTemplate.delete("test:user");// 判断key是否存在System.out.println(redisTemplate.hasKey("test:user"));// 设置key过期时间redisTemplate.expire("test:students", 10, TimeUnit.SECONDS);// keys命令在程序中不常用,通常都是去redis数据库中查的时候用
}

简化多次访问同一个key情况代码

    // 多次访问同一个key,可以简化不停传入key的操作// 方法:将key绑定到一个对象上@Testpublic void testBoundOperations() {String redisKey = "test:count";// BoundXXXOperations: XXX为要访问的数据类型,redisTemplates可将key绑定到该对象上BoundValueOperations operations = redisTemplate.boundValueOps(redisKey);// 累加操作,不用再传入key了operations.increment();operations.increment();operations.increment();operations.increment();operations.increment();// 获取System.out.println(operations.get());}

Redis中的事务

关系型数据库需要严格遵守ACID,而非关系型数据库不完全满足ACID四个特性

启用事务后,当redis收到命令时,不会立刻执行,而是放到队列里存着,直到提交事务时,才将队列中的命令批量执行

因此,在事务中不要查询数据,会无效,因此要么在事务前查,要么事务提交后查

redis支持声明式事务和编程式事务,但通常不用声明式事务

因为声明式事务只能精确到一个方法上(即给一个方法加上注解,将整个方法看作一个事务),这样的话,方法内部就无法进行查询了

通常用编程式事务将事务范围缩小

核心方法execute()

Redis 进行批量操作,可以使用 RedisTemplate 的 execute()方法。

execute() 方法,可以在一次连接中进行多个命令操作,执行完会自动关闭连接。

execute() 需要传入一个回调接口作为参数,SessionCallback参数 和 RedisCallback参数
SessionCallback 比 RedisCallck 更好些,优先使用 SessionCallback 。

使用SessionCallback , 还可以配合multi() 和 watch() 进行事务操作。

事务代码实例

@RunWith(SpringRunner.class)
@SpringBootTest
@ContextConfiguration(classes = CommunityApplication.class)
public class RedisTests {@Autowiredprivate RedisTemplate redisTemplate;// 编程式事务@Testpublic void testTransaction() {Object result = redisTemplate.execute(new SessionCallback() {// 在外层execute方法被调用时,底层自动调用匿名回调接口内的execute方法// 调用时会将执行命令的对象(RedisOperations)传入,利用这个对象来执行命令、管理事务// 返回的数据会返回到外层execute中,我们可以从外层execute方法上接收@Overridepublic Object execute(RedisOperations redisOperations) throws DataAccessException {// 事务之外// 定义key  tx为transaction事务的缩写String redisKey = "text:tx";// 事务:启用-ti'jiao// 启用事务redisOperations.multi();// 在事务中进行操作redisOperations.opsForSet().add(redisKey, "zhangsan");redisOperations.opsForSet().add(redisKey, "lisi");redisOperations.opsForSet().add(redisKey, "wangwu");// 在事务中查询没有效果,因为命令在队列里存着,直到提交事务时,批量执行System.out.println(redisOperations.opsForSet().members(redisKey));// 提交事务return redisOperations.exec();}});System.out.println(result);}}

参考文献

https://blog.csdn.net/sinat_32502451/article/details/133026414

存着,直到提交事务时,批量执行
System.out.println(redisOperations.opsForSet().members(redisKey));

            // 提交事务return redisOperations.exec();}});System.out.println(result);
}

}


# 参考文献https://blog.csdn.net/sinat_32502451/article/details/133026414https://blog.csdn.net/qulinchao/article/details/122190636

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

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

相关文章

springboot快速构建项目

1.Spring的基本步骤 2.构建项目 第一次下包速度比较慢&#xff0c;可以考虑使用镜像 至此项目构建完成 3.启动并配置数据库 新建一个数据库&#xff0c;新建一个表 下面这里也可以【重构-重命名】为yml后缀&#xff08;代码可粘下面的&#xff0c;后面有写&#xff09; Yml后…

FreeRTOS_day2

作业&#xff1a;1.使用ADC采样光敏电阻数值&#xff0c;如何根据这个数值调节LED灯亮度。 2.总结DMA空闲中断接收数据的使用方法 打开DAM,允许接收外部设备数据&#xff0c;调用中断接收回调函数

Eclipse调试技巧 条件断点 监视

实验代码 import java.util.Scanner;public class Test {// 判断n是否为质数public static boolean isPrime(int n){if (n < 2)return false;for (int i 2; i < n; i){if (n % i 0)return false;}return true;}public static void main(String[] args){Scanner scanne…

前端每日一练:深入理解CSS浮动、问题及清除浮动解决方案

深入理解CSS浮动、问题及解决方案 在CSS布局中&#xff0c;浮动&#xff08;float&#xff09;是一种常见的布局属性&#xff0c;用于控制元素在其父元素中的位置&#xff0c;使其可以浮动到左侧或右侧。然而&#xff0c;浮动也会引起一些常见的问题&#xff0c;主要涉及到高度…

专治Java底子差,线程操作篇(1)

&#x1f497;推荐阅读文章&#x1f497; &#x1f338;JavaSE系列&#x1f338;&#x1f449;1️⃣《JavaSE系列教程》&#x1f33a;MySQL系列&#x1f33a;&#x1f449;2️⃣《MySQL系列教程》&#x1f340;JavaWeb系列&#x1f340;&#x1f449;3️⃣《JavaWeb系列教程》…

[网络安全] PKI

一、PKI 概述 名称; 公钥基础设施 (Public Key Facility) 作用: 通过加密技术和数字签名保证信息安全 组成: 公钥机密技术、数字证书、CA、RA 二、信息安全三要素 机密性&#xff1a;确保仅信息发收双方 能看懂信息 完整性&#xff1a; 确保信息发收完整&#xff0c;不被破坏 …

最新基于R语言lavaan结构方程模型(SEM)技术应用

结构方程模型&#xff08;Sructural Equation Modeling&#xff0c;SEM&#xff09;是分析系统内变量间的相互关系的利器&#xff0c;可通过图形化方式清晰展示系统中多变量因果关系网&#xff0c;具有强大的数据分析功能和广泛的适用性&#xff0c;是近年来生态、进化、环境、…

前端每日一练:如何隐藏一个元素​?

css 中隐藏元素的方法有很多&#xff0c;但他们也各有差异&#xff0c;不同场景选择合适的方式能事倍功半&#xff01; 方式​ 占位​ 点击事件​ display: none​ ❌​ ❌​ opacity: 0​ ✅​ ✅​ visibility: hidden​ ✅​ ❌​ clip-path: circle(0)​ ✅​…

支小蜜校园防欺凌系统如何有效应对学生霸凌?

学生霸凌不仅直接伤害到被霸凌者的身心健康&#xff0c;也对整个校园的和谐氛围构成了威胁。为了应对这一问题&#xff0c;校园防欺凌系统应运而生&#xff0c;成为维护校园安全、保护学生权益的重要工具。那么当校园防欺凌系统面对学生霸凌时&#xff0c;该如何有效应对呢&…

STM32CubeMX学习笔记8 -ADC

1. ADC简介 ADC 是Analog-to-Digital Converter的缩写。指模/数转换器或者模拟/数字转换器。是指将连续变量的模拟信号转换为离散的数字信号的器件。典型的模拟数字转换器将模拟信号转换为表示一定比例电压值的数字信号。简单地说就是将模拟电压值&#xff0c;转换成对应的肉眼…

ACM题解Day10|总结篇|进制转化,GCD ,LCM ,二分答案

&#x1f525;博客介绍&#xff1a; 27dCnc [Cstring中find_first_not_of()函数和find_last_not_of()函数-CSDN博客] 方差,期望 概率 今日打卡: 算法周总结 ACM题解Day3| To Crash or not To Crash,Integer Prefix ,I don’t want to pay for the Late Jar-CSDN博客 第3题:…

单例服务拆分为分布式架构

将独立业务服务拆分为分布式 为啥会有这个想法&#xff1f;因为我要造锤子&#xff0c;拿着造好的锤子&#xff0c;去找锤子&#xff0c;没有造锤子的经验无法找一个造锤子的坑。 现有情况说明 单机软件&#xff1a;就是将软件安装在自己的电脑上&#xff0c;自己用的那种&…

回文数0102

学习回文数&#xff0c;突发奇想加入了键盘输入&#xff0c;最后形成的代码&#xff1a;如下public static void main(String[] args) {Scanner scnew Scanner(System.in);System.out.println("请输入一串数字");int xsc.nextInt();int num0;//利用while循环获取数字…

硬核程序员接单指南,速看!

程序员单没接着&#xff0c;时间还浪费了&#xff1f;惹得一身晦气。遇上了1k开发一个“淘宝”网站的“深井”&#xff1f;不是来下单的&#xff0c;倒像是来许愿的……估摸着是把程序员当阿拉丁神灯。 莫非那些兼职月入3k&#xff0b;的人&#xff0c;都是托儿&#xff1f;带着…

【MySQL】索引下推

索引下推&#xff08;ICP&#xff09;是一种在存储引擎层使用过滤数据的优化方式。使用ICP的好处在于其可以减少存储引擎必须访问基表的次数和MySQL服务器必须访问存储引擎的次数。但ICP的加速效果取决于存储引擎内通过ICP筛掉的数据比例。   举个例子 CREATE INDEX zip_las…

剑指offer面试题26 复杂链表的复制

考察点 链表遍历知识点 题目 分析 这道题目要求复制链表&#xff0c;链表结点除了值和next指针以外还有一个指针指向该链表中任意一个结点。这道题目最直观的解法就是先把含有next指针的链表复制出来&#xff0c;然后再次遍历链表设置第二个指针&#xff0c;方法是判断下第二…

网络编程套接字(1)—网络编程基础

目录 一、为什么需要网络编程? 二、什么是网络编程 三、网络编程中的基本概念 1、发送端和接收端 2、请求和响应 3、客户端和服务端 四、常见的客户端服务端模型 1、一问一答模型 2、一问多答模型 3、多问一答模型 4、多问多答模型 一、为什么需要网络编程? 为什么…

一次gitlab 502故障解决过程

通过top,发现prometheus进程占用CPU接近100%&#xff0c;这肯定有点异常。gitlab-ctl tail prometheus 发现有报错的情况&#xff0c;提示空间不足。暂时不管空间的问题。 2024-03-07_05:48:09.01515 ts2024-03-07T05:48:09.014Z callermain.go:1116 levelerror err"open…

ItemTemplateSelector 数据源选择器,控件模板选择器

背景&#xff1a;GridView、ListBox中的数据&#xff0c;如果需要不同的数据显示不同的模板&#xff0c;这个时候适合使用ItemTemplateSelector 1、window.Resources中定义两个数据模板&#xff0c;同一个数据集合&#xff0c;不同的数据使用不同的数据模板 <DataTemplate …

【c】找到与给定字符相同的字符

给定程序中&#xff0c;函数fun的功能是&#xff1a;在形参s所指字符串中寻找与参数c相同的字符&#xff0c;并在其后插入一个与之相同的字符&#xff0c;若找不到相同的字符则函数不做任何处理。 例如&#xff0c;s所指字符串为&#xff1a;baacda&#xff0c;c中的字符为&am…