在Spring里如何玩转Redis操作
目录
创建项目
编辑 配置Redis
创建类
StringRedisTemplate
set / get
list
set
Hash
zset
新年快乐!!!!
创建项目
选中maven项目,然后选择java8,输入名称之后,点击next。
随后选择依赖:
配置Redis
找到配置文件 application.properties:
当然你也可以将其改为yml:
这里我们使用yml文件:
添加配置:
spring:
redis:
host: 127.0.0.1
port: 8888
这里通过ssh转发,来实现连接服务器上的Redis服务器。
创建类
创建一个MyController类
spring中使用StringRedisTemplate来操作Redis,其实最原始的提供的类是RedisTemplate,但是太麻烦了,现在的StringRedisTemplate是RedisTemplate的子类,专门用来处理 文本数据的。
MyController内容如下:
package com.example.redisbyspring;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.web.bind.annotation.RestController;
@RestController
public class MyController {
@Autowired
private StringRedisTemplate redisTemplate;
}
后续将在这个类中进行Redis的操作。
StringRedisTemplate
通过在一个请求方法中进行对象.的操作,发现好像和我们预想的不一样:
通过这个类的实例对象,并没有发现很直观的有get和set方法,但是似乎他们的前面都加上了posFor。这是为什么?
其实,此处的Template就是把这些操作Redis的方法,分成了几个类别,例如,操作list的是一个类,他就是opsForList(),以此类推做了进一步封装:
后续的stringRedisTemplate是StringRedisTemplate的子类。
在进行jedis集成spring的测试代码中,需要清除干扰项目,也就是里面可能已经存在一些key,对我们后面的测试造成影响,需要使用flashAll来清除所有的key。
但是我们翻阅了stringRedisTemplate的方法,发现没有flashall操作:
RedisTemplate留了一个后手,让我们随时可以执行到Redis的原生命令。Redis集成spring中有一个 execute方法,用来执行Redis的原生命令。
里面有一个RedisCallBack是一个回调函数:
public interface RedisCallback<T> {
@Nullable
T doInRedis(RedisConnection connection) throws DataAccessException;
}
输入相关参数就可以进行执行Redis原生命令了:
redisTemplate.execute((RedisConnection connection) -> {
connection.flushAll();
});
但是有个问题,就是这段代码的execute会报错:
这是什么回事?这是因为当前的execute方法会有一个返回结果,但是当前不需要返回什么,就返回一个null即可:
redisTemplate.execute((RedisConnection connection) -> {
connection.flushAll();
return null;
});
set / get
使用StringRedisTemplate的实例中的方法来 进行set和get方法操作Redis。
package com.example.redisbyspring;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.RestController;
@RestController
public class MyController {
@Autowired
private StringRedisTemplate redisTemplate;
@GetMapping("/testString")
@ResponseBody
public String testString() {
redisTemplate.opsForValue().set("key1","value1");
redisTemplate.opsForValue().set("key2","value2");
redisTemplate.opsForValue().set("key3","value3");
String ret1 = redisTemplate.opsForValue().get("key1");
System.out.println(ret1);
String ret2 = redisTemplate.opsForValue().get("key2");
System.out.println(ret2);
String ret3 = redisTemplate.opsForValue().get("key3");
System.out.println(ret3);
return "ok";
}
}
浏览器访问接口:
返回:
控制台输出:
list
@GetMapping("/testList")
@ResponseBody
public String testList() {
redisTemplate.execute((RedisConnection connection) -> {
connection.flushAll();
return null;
});
// list的lpush
redisTemplate.opsForList().rightPush("key","111");
// list一次性添加多个元素
redisTemplate.opsForList().rightPushAll("key","222","333","444");
// 此时的列表内容为[111,222,333,444]
// pop
redisTemplate.opsForList().leftPop("key");
redisTemplate.opsForList().rightPop("key");
// 此时list表的内容为[222,333]
// list的lrange
List<String> list = redisTemplate.opsForList().range("key",0, -1);
System.out.println(list);
return "listOk";
}
访问对应的链接,输出:
set
@GetMapping("/testSet")
@ResponseBody
public String testSet() {
redisTemplate.execute((RedisConnection connection) -> {
connection.flushAll();
return null;
});
// set的sadd
redisTemplate.opsForSet().add("key","111","222","333");
// set的smembers
Set<String> set = redisTemplate.opsForSet().members("key");
System.out.println(set);
// set的sismember
Boolean bool = redisTemplate.opsForSet().isMember("key","111");
System.out.println(bool);
// set中的scard
Long count = redisTemplate.opsForSet().size("key");
System.out.println(count);
// set中srem
count = redisTemplate.opsForSet().remove("key","111");
System.out.println("删除的个数:" + count);
set = redisTemplate.opsForSet().members("key");
System.out.println(set);
return "setOk";
}
访问此链接,输出:
Hash
@GetMapping("/testHash")
@ResponseBody
public String testHash() {
redisTemplate.execute((RedisConnection connection) -> {
connection.flushAll(); // 刷新Redis数据
return null;
});
// hash中的hset
redisTemplate.opsForHash().put("key","f1","v1");
// hmset
Map<String,String> map = new HashMap<>();
map.put("f2","v2");
map.put("f3","v3");
redisTemplate.opsForHash().putAll("key",map);
// hget
String ret = (String) redisTemplate.opsForHash().get("key","f1");
System.out.println(ret);
// hexists
Boolean exists = redisTemplate.opsForHash().hasKey("key","f1");
System.out.println(exists);
// hdel
Long numsOfDel = redisTemplate.opsForHash().delete("key","f1");
System.out.println(numsOfDel);
// hlen
Long len = redisTemplate.opsForHash().size("key");
System.out.println(len);
// hkeys
Set<Object> set = redisTemplate.opsForHash().keys("key");
System.out.println(set);
// hval
List<Object> list = redisTemplate.opsForHash().values("key");
System.out.println(list);
Map<Object,Object> map1 = redisTemplate.opsForHash().entries("key");
System.out.println(map1);
return "hashOK";
}
输出:
zset
@GetMapping("/testZset")
@ResponseBody
public String testZset() {
redisTemplate.execute((RedisConnection connection) -> {
connection.flushAll(); // 刷新Redis数据
return null;
});
// zadd
redisTemplate.opsForZSet().add("key","zhangsan",10.2);
redisTemplate.opsForZSet().add("key","lisi",11.3);
redisTemplate.opsForZSet().add("key","wangwu",12.4);
// zrange
Set<String> set = redisTemplate.opsForZSet().range("key",0, -1);
System.out.println(set);
// zrangewithScores
Set<ZSetOperations.TypedTuple<String>> setWithScores = redisTemplate.opsForZSet().rangeWithScores("key",0,-1);
System.out.println(setWithScores);
// zscore
Double scoreOfLisi = redisTemplate.opsForZSet().score("key","lisi");
System.out.println(scoreOfLisi);
// zrem
redisTemplate.opsForZSet().remove("key","lisi");
setWithScores = redisTemplate.opsForZSet().rangeWithScores("key",0,-1);
System.out.println(setWithScores);
// zrank
Long rank = redisTemplate.opsForZSet().rank("key","lisi");
System.out.println(rank);
rank = redisTemplate.opsForZSet().rank("key","wangwu");
System.out.println(rank);
return "zsetOK";
}
输出:
更多详细内容可以查阅spring官方文档:
Spring BootLevel up your Java code and explore what Spring can do for you.https://spring.io/projects/spring-boot
推荐阅读
-
趣谈留言队列,搞清楚留言队列到底是什么!-说到消息队列,洪觉大概能猜到人们听到消息队列的反应,大致可以分为以下几类人。 第一类人,懵懵懂懂,刚上大学接触编程,还没用过消息队列,甚至还以为消息队列就是代码里面要新建一个List之类的;第二类人,听过消息队列,了解消息队列,但具体是什么还不是太明白,只知道一说到消息队列,脑海里马上出现了三组词,削峰、异步、解耦;第三类人,用过消息队列,对它有一定了解,但不知道为什么要这样设计,消息队列有什么样的前世今生,是如何演化到现在的模式的?**第四类人,已经对消息队列有了足够的了解,可以阅读本帖作为复习和温习。**你属于哪一类?无论你对消息队列了解多少,读完这篇文章后,我相信你都会有所收获。 什么是消息队列?我们为什么要使用消息队列?真的只是因为它看起来很勉强、很常用吗?当然不是,一项技术的出现往往是为了解决某种痛点,我们就从这个痛点出发,看看消息队列到底是为了解决什么问题而诞生的。 相信大家在工作之前,或者工作中接触单片机的次数会多一点,不管什么业务都一股脑塞进一个系统里,这种情况下接触消息队列的场景会比较少。但随着业务的增长,量上去了,单机系统就很难维护了,也扛不住并发量的增长,就需要把原来的单体应用拆分成多个服务。例如,牛奇网采用分布式架构,将原来的单体系统拆分成用户服务、题库服务、求职服务、论坛服务等,每个分布式节点都有一个集群,保证高可用性。 那虽然在这样的微服务架构下,如果某个核心业务并发量过大,系统就扛不住了。比如淘宝、淘票票、拼多多、京东等电商场景中的支付场景,你在某宝下单并支付后,调用支付服务,完成支付后,还需要更新订单的状态,这个时候就需要调用订单服务,那我们平时也下单,除了简单完成这些操作外,还会给你相应的积分;商家也会收到订单消息,并给您发送旺旺消息,确认订单无误;同时,也会给您发送消息,确认订单无误。确认订单无误;同时您还可以查看您的物流状态;还有系统为了给您推荐更适合您的商品,会根据您的订单做类似的推荐等等,我说的这些都是当我们下单后,肉眼可以感知到系统所做的动作。 **一个支付动作如果还需要调用那么多服务,等他们响应成功,最后再告诉用户你支付成功了,用户在系统中的整个体验会非常糟糕。**设想一下,假设请求服务+处理请求+响应总共需要 50ms,我们上面列出的场景:支付服务、订单服务、积分服务、商家服务、物流服务、推荐服务,总共需要 300ms。
-
阿里味 "的《Redis核心实践全彩手册》给你,还学不会转行--Redis基本是必考点。在 "阿里味 "的《Redis核心实战全彩手册》里,你还是学不会转行--Redis基本是必考点: - Redis 常见的性能问题有哪些?Redis 最常见的性能问题有哪些,如何解决?--性能相关 - Redis 缓存的雪崩、击落和穿透到底意味着什么?如何处理?--缓存相关 - Redis 主从集群有哪些常见问题?如何解决?--可用性 - 现有的 Redis 实例有 6GB 的存储空间,预计将来会扩展到 32GB,你能提供解决方案并分析其优势和潜在问题吗?--可扩展性相关 毕竟,10 家公司中至少有 8 家的架构系统中都有 Redis,基本上可以说是 IT 基础架构的必备系统。 因此,Redis 的开发和运维是很多大厂的重要工作,也是我们必须掌握的技术栈。 不过,Redis 毕竟是一个复杂的键值数据库,在实际使用中,有非常多的技术点需要注意,比如:各种数据结构、数据持久化机制、分片集群、主从集群等等。 一不小心,性能就会每况愈下,失去 "快 "的最大特点!
-
在Spring Boot中如何设置logback(通过Spring配置类操作)
-
在Spring里如何玩转Redis操作
-
如何轻松搞定在使用aliyun-oss-spring-boot-starter时的依赖导入错误:只需在pom.xml里的
部分添加所需依赖 -
在Docker里如何检查JVM状态:轻松操作jmap和jstat工具
-
在Python里,如何轻松运用Paramiko库进行远程服务器连接,并实现文件的上传与下载操作
-
在Excel里如何轻易反向操作公式:单个变量的求解方法
-
玩转Java底层:JMX详解 - jconsole与自定义MBean监控工具的实际应用与区别" 在日常JVM调优中,我们熟知的jconsole工具通过JMX包装的bean以图形化形式展示管理数据,而像jstat和jmap这类内建监控工具则由JVM直接支持。本文将以jconsole为例,深入讲解其实质——基于JMX的MBean功能,包括可视化界面上的bean属性查看和操作调用。 MBeans在jconsole中的体现是那些可观察的组件属性和方法,如上图所示,通过名为"Verbose"的属性能看到其值为false,同时还能直接操作该bean的方法,例如"closeJerryMBean"。 尽管jconsole给我们提供了直观的可视化界面,但请注意,这里的MBean并非固定不变,开发者可根据JMX提供的接口将自己的自定义bean展示到jconsole。以下步骤展示了如何创建并注册一个名为"StudyJavaMBean"的自定义MBean: 1. 首先定义接口`StudyJavaMBean`,接口需遵循MBean规范,即后缀为"MBean"且包含getter方法代表属性,如`getApplicationName`,和无返回值的setter方法代表操作,如`closeJerryMBean`。 ```java public interface StudyJavaMBean { String getApplicationName(); void closeJerryMBean(); } ``` 2. 编写接口的实现类`StudyJavaMBeanImpl`,实现接口中的方法: ```java public class StudyJavaMBeanImpl implements StudyJavaMBean { @Override public String getApplicationName() { return "每天学Java"; } @Override public void closeJerryMBean() { System.out.println("关闭Jerry应用"); } } ``` 3. 在代码中注册自定义MBean,涉及的关键步骤包括: - 获取平台MBeanServer - 定义ObjectName,指定唯一的MBean标识符 - 注册MBean到服务器 - 启动RMI连接器服务,以便jconsole能够访问 ```java public void registerMBean() throws Exception { // ... 具体实现省略 ... } ``` 实际运行注册后的MBean,您将在jconsole中发现并查看自定义bean的属性和调用相关方法。然而,这种方式相较于传统的属性/日志查看和HTTP接口,实用性相对有限,可能存在潜在的安全风险。但不可否认的是,JMX及其MBean机制对于获取操作系统信息、内存状态等关键性能指标仍然具有重要价值。例如: 1. **获取操作系统信息**:通过JMX MBean,可以直接获取到诸如CPU使用率、操作系统版本等系统级信息,这对于资源管理和优化工作具有显著帮助。
-
在Seurat工具里如何进行细胞聚类操作