Spring中间件之Redis基础
复习目标
-
掌握Redis的数据类型
-
掌握Redis的常用命令
-
掌握Spring Data Redis操作Redis的常用方法
Resis命令前瞻
string | hash | list | set | zset | |
---|---|---|---|---|---|
增加 | set key value 判定性添加:setnx key value |
hset key field value | 左压入:lpush key value 右压入:rpush key value |
sadd key value [value1 value2] | zadd key score value [score1 value1] |
多添加 | mset key value key1 value1 | zset key value key1 value1 | |||
删除 | del key | 部分:hdel key field [field1] 所有:del key |
左弹出:lpop key 右同理 |
srem key value | zrem key value |
查询 | get key | 查完整一条:hgetall key 查一条的指定键:hget key field |
lrange key [始 末] | 查全部:smembers key | 升序:zrange key start end [withscores] 降序:zrevrange key start end [withscores] |
其他 | 自增(减)操作:incr/decr key 增的时候设置过期时间: setex key second value |
获取所有hkey:hkeys key 获取所有hvalue:hvals key |
列表长度:llen key | 求集合的交集:sinter key1 key2 求集合的并集:sunion key1 key2 求集合的差集:(逐一:顺序问题)sdiff key1 key2 等价key1-key2 |
-
模糊查询键
keys * -
删除多个键
del key key .... -
根据键判断值类型
type key -
选择数据库
select 0~15 -
清空当前数据库 (了解)
flushdb -
清空所有数据库(了解)
flushall
Redis介绍(了解)
Redis介绍
Redis是一个基于内存的key-value结构的数据库
主要特点
- 基于内存存储,读写性能高 – Redis读(查询)的速度是11_0000次/S
- 适合存储热点数据(商品、资讯、新闻)
- 它存储的value类型比较丰富,也称为结构化NoSQL数据库
NoSQL介绍
NoSQL(Not Only SQL )不仅仅是SQL,泛指非关系型数据库,NoSQL数据库并不是要取代关系型数据库,而是关系型数据库的补充。
Redis的安装和启动
下载
- Reids官网地址:http://redis.io
- 中文网地址:https://www.redis.net.cn/
- GitHub地址:https://github.com/MSOpenTech/redis/tags
安装
windows绿色版,解压即用(无中文路径)
目录结构
目录或文件 | 作用 |
---|---|
redis-benchmark | 性能测试工具 |
redis-check-aof | AOF文件修复工具 |
redis-check-dump | RDB文件检查工具(快照持久化文件) |
redis-cli | 命令行客户端 |
redis-server | 启动redis服务器 |
redis.windows.conf | redis核心配置文件 |
启动服务器
启动客户端
自带客户端为命令行模式,同样双击启动,一定要先启动服务端,再启动客户端
Redis的命令(重点)
Redis数据结构
Redis采用的是键值对存储,键的类型只能为字符串,值支持五种数据类型:
- 字符串:String
- 哈希:HashMap
- 双向链表:LinkedList
- 无序集合:HashSet
- 有序集合:LinkedHashSet
Redis中两单词间用 “ :” 分割,类似数据库中用" _"。
String字符串
字符串类型是Redis中最为基础的数据存储类型
命令 | 描述 |
---|---|
SET | 添加或者修改已经存在的一个String类型的键值对 |
GET | 根据key获取String类型的value |
MSET | 批量添加多个String类型的键值对 |
MGET | 根据多个key获取多个String类型的value |
INCR | 让一个整型的key自增1 |
INCRBY | 让一个整型的key自增并指定步长,例如:incrby num 2 让num值自增2 |
INCRBYFLOAT | 让一个浮点类型的数字自增并指定步长 |
SETNX | 添加一个String类型的键值对,前提是这个key不存在,否则不执行 |
SETEX | 添加一个String类型的键值对,并且指定有效期 |
* 新增
set key value
* 查询
get key
* 删除
del key
* 新增的时候设置过期时间
setex key second value//
* 根据键判断记录是否存在
exists key
* 查看剩余时间
ttl key
* 新增的时候判断可以是否存在
setnx key value
* 自增(减)操作:(MySQL自增器)
incr/decr key
Hash哈希
Hash类型极其类似于java中的Map,值里面可以存放一组组的键值对
该类型非常适合于存储java中对象的信息
Hash的常见命令有:
命令 | 描述 |
---|---|
HSET key field value | 添加或者修改hash类型key的field的值 |
HGET key field | 获取一个hash类型key的field的值 |
HMSET | hmset 和 hset 效果相同 ,4.0之后hmset可以弃用了 |
HMGET | 批量获取多个hash类型key的field的值 |
HGETALL | 获取一个hash类型的key中的所有的field和value |
HKEYS | 获取一个hash类型的key中的所有的field |
HVALS | 获取一个hash类型的key中的所有的value |
HINCRBY | 让一个hash类型key的字段值自增并指定步长 |
HSETNX | 添加一个hash类型的key的field值,前提是这个field不存在,否则不执行 |
部分命令案例:
* 新增
hset key hkey hvalue
* 查询
所有
hgetall key
单个
hget key hkey
* 获取所有hkey
hkeys key
* 获取所有hvalue
hvals key
* 删除
单个
hdel key hkey
所有
del key
List列表
List类型底层是一个双向字符串链表。里面的元素是有序的,可重复的
我们可以从链表的任何一端进行元素的增删
List的常见命令有
命令 | 描述 |
---|---|
LPUSH key element … | 向列表左侧插入一个或多个元素 |
LPOP key | 移除并返回列表左侧的第一个元素,没有则返回nil |
RPUSH key element … | 向列表右侧插入一个或多个元素 |
RPOP key | 移除并返回列表右侧的第一个元素 |
LRANGE key star end | 返回一段角标范围内的所有元素 |
BLPOP和BRPOP | 与LPOP和RPOP类似,只不过在没有元素时等待指定时间,而不是直接返回nil |
新增
- 左压入lpush key value
- 右压入rpush key value
查询元素
lrange key [开始索引 结束索引]
列表长度
llen key
* 删除元素
左弹出
lpop key
右弹出
rpop key
BLPOP和BRPOP:与LPOP和RPOP类似,只不过在没有元素时等待指定时间,而不是直接返回nil,可以用来实现阻塞队列
Set集合
Set类型底层是一张hash表。里面的元素是无序的,不可重复的
* 新增
sadd key value1 [value2 value3]
* 查看集合元素
smembers key
* 查询集合元素数量
scard key
* 删除元素
srem key value
* 随机弹出元素
spop key
* 判断一个元素是否存在于set中
SISMEMBER key value
* 求集合的交集:
sinter key1 key2
* 求集合的并集:
sunion key1 key2
* 求集合的差集:(逐一:顺序问题)
sdiff key1 key2
ZSet集合
Zset,也称sortedSet, 在Set的基础上,加入了有序功能,在添加元素的时候,允许指定一个分数,它会按照这个分数排序
SortedSet的常见命令有
命令 | 描述 |
---|---|
ZADD key score member | 添加一个或多个元素到sorted set ,如果已经存在则更新其score值 |
ZREM key member | 删除sorted set中的一个指定元素 |
ZSCORE key member | 获取sorted set中的指定元素的score值 |
ZRANK key member | 获取sorted set 中的指定元素的排名 |
ZCARD key | 获取sorted set中的元素个数 |
ZCOUNT key min max | 统计score值在给定范围内的所有元素的个数 |
ZINCRBY key increment member | 让sorted set中的指定元素自增,步长为指定的increment值 |
ZRANGE key min max | 按照score排序后,获取指定排名范围内的元素 |
ZRANGEBYSCORE key min max | 按照score排序后,获取指定score范围内的元素 |
ZDIFF、ZINTER、ZUNION | 求差集、交集、并集 |
注意:所有的排名默认都是升序,如果要降序则在命令的Z后面添加REV
即可
* 新增
zadd key score value [score value score value]
* 查询
升序
zrange key start end [withscores]
降序
zrevrange key start end [withscores]
* 删除
zrem key value
Zset命令补充:
Redis之Sorted Set数据类型API及应用场景解析(一)-阿里云开发者社区 (aliyun.com)
通用命令
* 模糊查询键
keys *
* 删除多个键
del key key ....
* 根据键判断值类型
type key
* 根据键判断值是否存在
exists key
* 设置键过期时间
expire key 过期时间(单位为秒)
* 选择数据库
select 0~15
* 清空当前数据库 (了解)
flushdb
* 清空所有数据库(了解)
flushall
Redis图形客户端
安装软件
Navicat最新版支持Redis了,双击安装即可
建立连接
Redis Java客户端
Jedis的使用(了解)
Redis作为一款优秀的缓存服务器存在,大多数语言都提供了连接Redis的驱动包,在java中,比较出名的是Jedis和Redisson,我们今天以Jedis为例学习,看看如何是用程序操作redis。
JedisAPI
方法 | 解释 |
---|---|
new Jedis(host, port) | 创建jedis对象,参数host是redis服务器地址,参数port是redis服务端口 |
set(key,value) | 设置字符串类型的数据 |
get(key) | 获得字符串类型的数据 |
hset(key,field,value) | 设置哈希类型的数据 |
hget(key,field) | 获得哈希类型的数据 |
lpush(key,values) | 设置列表类型的数据 |
lpop(key) | 列表左面弹栈 |
rpop(key) | 列表右面弹栈 |
del(key) | 删除指定的key |
Jedis使用
创建工程,引入依赖
<dependencies>
<dependency>
<groupId>redis.clients</groupId>
<artifactId>jedis</artifactId>
<version>2.9.3</version>
</dependency>
</dependencies>
测试类
package test;
import redis.clients.jedis.Jedis;
public class JedisTest {
public static void main(String[] args) {
// 1.创建连接对象
Jedis jedis = new Jedis("127.0.0.1",6379);
// 2. 设置密码
jedis.auth("132537");
// 3. 选择库(默认是下标为0的库)
jedis.select(0);
// 设置String类型
jedis.set("student","zbz");
// 查询String类型
String student = jedis.get("student");
System.out.println(student);
// 关闭连接
jedis.close();
}
}
Jedis连接池
Jedis本身是线程不安全的,并且频繁的创建和销毁连接会有性能损耗,因此我们推荐大家使用Jedis连接池代替Jedis的直连方式
// 工具类
public class JedisConnectionFactory {
private static final JedisPool jedisPool;
static {
//配置连接池
JedisPoolConfig jedisPoolConfig = new JedisPoolConfig();
jedisPoolConfig.setMaxTotal(8);
jedisPoolConfig.setMaxIdle(8);
jedisPoolConfig.setMinIdle(0);
jedisPoolConfig.setMaxWaitMillis(200);
//创建连接池对象 ip 端口 超时时间 密码
jedisPool = new JedisPool(jedisPoolConfig,"192.168.230.88",6379,1000,"132537");
}
public static Jedis getJedis(){
return jedisPool.getResource();
}
}
demol
package com.itheima.test;
import redis.clients.jedis.Jedis;
import redis.clients.jedis.JedisPool;
import redis.clients.jedis.JedisPoolConfig;
import java.util.Map;
public class JedisPoolTest {
public static void main(String[] args) {
// 连接池配置对象
JedisPoolConfig jedisPoolConfig = new JedisPoolConfig();
jedisPoolConfig.setMaxTotal(500);// 最大连接数
// 创建连接池对象
JedisPool jedisPool = new JedisPool(jedisPoolConfig, "127.0.0.1", 6379);
// 从连接池中获取连接
Jedis jedis = jedisPool.getResource();
// api操作
Map<String, String> map = jedis.hgetAll("user_1001");
System.out.println(map);
// 释放资源(归还连接)
jedis.close();
}
}
SpringDataRedis(重点)
介绍
Spring Data Redis提供了从Spring应用程序轻松配置和访问Redis的功能
- 提供了对不同Redis客户端的整合(
Lettuce
和Jedis
) - 提供了
RedisTemplate
统一API来操作Redis - 支持Redis的发布订阅模型
- 支持Redis哨兵和Redis集群
- 支持基于Lettuce的响应式编程【链式编程】
- 支持基于JDK、JSON、字符串、Spring对象的数据序列化及反序列化
- 支持基于Redis的JDKCollection实现
RedisTemplate
模板工具类,提供了redis各种操作
- ValueOperations:简单键值对操作 String
- SetOperations:set类型数据操作 set
- ZSetOperations:zset类型数据操作 sortedset---->zset
- HashOperations:针对hash类型的数据操作 hash
- ListOperations:针对list类型的数据操作 list
环境搭建
调整(覆盖)坐标
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.4.5</version>
</parent>
<dependencies>
<dependency>
<groupId>redis.clients</groupId>
<artifactId>jedis</artifactId>
<version>2.9.3</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<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>
</dependencies>
添加配置文件application.yml
spring:
redis:
host: localhost
port: 6379
database: 0 # 操作的是0号数据库
lettuce: #连接池配置
pool:
max-active: 8 #最大连接数
max-wait: 1ms #连接池最大阻塞时间(等待时间)
max-idle: 4 #连接池中的最大空闲连接
min-idle: 0 #连接池中的最小空闲连接
创建测试类
package com.it.test;
import com.it.domain.User;
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 org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.data.redis.core.ValueOperations;
// junit5的版本默认可以运行器切换为spring的
@SpringBootTest
public class RedisTest {
// 使用此工具类存储的java对象,底层会将对象进行jdk序列化
@Autowired
private RedisTemplate redisTemplate;
// 使用此资工具类只能存储字符串类型的数据
@Autowired
private StringRedisTemplate stringRedisTemplate;
// 父工具类操作String类型
@Test
public void test01()throws Exception{
ValueOperations valueOperations = redisTemplate.opsForValue();
valueOperations.set("1002","张三" );
User user = new User();
user.setId(1);
user.setUsername("hehe");
valueOperations.set("1", user);
}
// 子工具类操作String类型
@Test
public void test02()throws Exception{
ValueOperations<String, String> stringValueOperations = stringRedisTemplate.opsForValue();
stringValueOperations.set("1003", "张三");
}
}
API
操作字符串类型数据
// 子工具类操作String类型
@Test
public void test02()throws Exception{
ValueOperations<String, String> stringValueOperations = stringRedisTemplate.opsForValue();
// 存(修改)
// stringValueOperations.set("1003", "张三");
// 取
// String value = stringValueOperations.get("1003");
// System.out.println(value);
// 删除
// stringRedisTemplate.delete("1003");
// 存储数据时,指定存活时间(场景:短信验证码)
// stringValueOperations.set("sms:13800138000", "7745", Duration.ofMinutes(5));
// 链式编程
stringRedisTemplate.opsForValue().set("sms:13800138000", "7745", Duration.ofMinutes(5));
}
操作哈希类型数据
// 子工具类操作Hash类型
@Test
public void test03() throws Exception {
// 获取hash类型操作对象
HashOperations<String, Object, Object> stringHashOperations = stringRedisTemplate.opsForHash();
// 存
stringHashOperations.put("h1001", "name", "zhangsan");
stringHashOperations.put("h1001", "age", "18");
stringHashOperations.put("h1001", "sex", "man");
// 获取一个元素
System.out.println(stringHashOperations.get("h1001", "name"));
System.out.println("-------------------");
// 取出所有的hkey
Set<Object> keys = stringHashOperations.keys("h1001");
for (Object key : keys) {
System.out.print(key);
System.out.println("=" + stringHashOperations.get("h1001", key));
}
System.out.println("-------------------");
// 直接获取所有hvalue
List<Object> values = stringHashOperations.values("h1001");
for (Object value : values) {
System.out.println(value);
}
// 删除一个元素
stringHashOperations.delete("h1001", "age");
// 删除整个map
stringRedisTemplate.delete("h1001");
}
操作列表类型数据
// 子工具类操作list类型
@Test
public void test04()throws Exception{
// 获取list类型操作对象
ListOperations<String, String> stringListOperations = stringRedisTemplate.opsForList();
// 左压入
// stringListOperations.leftPushAll("list", "a","b");
// 右压入
// stringListOperations.rightPushAll("list","c","d" );
// 查询:从左到右
List<String> list = stringListOperations.range("list", 0, -1);
for (String s : list) {
System.out.print(s);
}
// 左弹出
stringListOperations.leftPop("list");
// 右弹出
stringListOperations.rightPop("list");
// 查询:从左到右
List<String> list2 = stringListOperations.range("list", 0, -1);
for (String s : list2) {
System.out.print(s);
}
}
操作集合类型数据
// 子工具类操作set类型
@Test
public void test05()throws Exception{
// 获取set类型操作对象
SetOperations<String, String> stringSetOperations = stringRedisTemplate.opsForSet();
// 存
stringSetOperations.add("lol","vn","js","gl","zx");
// 取
Set<String> lol = stringSetOperations.members("lol");
System.out.println(lol);
// 删除指定元素
stringSetOperations.remove("lol","zx");
}
操作有序集合类型数据
// 子工具类操作zset类型
@Test
public void test06()throws Exception{
// 获取zset操作对象
ZSetOperations<String, String> stringZSetOperations = stringRedisTemplate.opsForZSet();
// 存
stringZSetOperations.add("wangzhe", "anqila", 60);
stringZSetOperations.add("wangzhe", "llw", 70);
stringZSetOperations.add("wangzhe", "wzj", 80);
stringZSetOperations.add("wangzhe", "houyi", 90);
// 升序(根据索引个数查询)
System.out.println(stringZSetOperations.range("wangzhe", 0, -1));
// 降序(根据索引个数查询)
System.out.println(stringZSetOperations.reverseRange("wangzhe", 0, -1));
// 升序(根据分值范围查询)
System.out.println(stringZSetOperations.rangeByScore("wangzhe", 80, 100));
// 降序(根据分值范围查询)
System.out.println(stringZSetOperations.reverseRangeByScore("wangzhe", 70, 100));
// 查询时包含分值,升序(根据索引个数查询)
Set<ZSetOperations.TypedTuple<String>> typedTuples = stringZSetOperations.rangeWithScores("wangzhe", 0, -1);
for (ZSetOperations.TypedTuple<String> typedTuple : typedTuples) {
System.out.print(typedTuple.getScore());
System.out.print(typedTuple.getValue());
System.out.println("");
}
}
通用操作
// 通用操作
@Test
public void test07()throws Exception{
// 模糊查询key = keys*
System.out.println(stringRedisTemplate.keys("l*"));
// 判断key是否存在
System.out.println(stringRedisTemplate.hasKey("sms:13800138000"));
}
配置类
RedisTemplate可以接收任意Object作为值写入Redis,只不过写入前会把Object序列化为字节形式,默认是采用JDK序列化
,会有中文乱码
缺点:
- 可读性差
- 内存占用较大
那么如何解决以上的问题呢?
方案一 通过自定义RedisTemplate序列化的方式来解决
注意:这段代码直接复制即可
//Redis配置类
//当前配置类不是必须的,因为 Spring Boot 框架会自动装配 RedisTemplate 对象,
//但是默认的key序列化器为JdkSerializationRedisSerializer,导致我们存到Redis中后的数据和原始数据有差别
@Configuration
public class RedisConfig extends CachingConfigurerSupport {
@Bean
public RedisTemplate<Object, Object> redisTemplate(RedisConnectionFactory connectionFactory) {
// 创建RedisTemplate对象
RedisTemplate<Object, Object> redisTemplate = new RedisTemplate<>();
// 2.设置连接工厂
// 设置Key的序列化器 默认是JdkSerializationRedisSerializer
redisTemplate.setKeySerializer(new StringRedisSerializer());
redisTemplate.setHashKeySerializer(new StringRedisSerializer());
// 设置value的序列化器 默认是JdkSerializationRedisSerializer
redisTemplate.setValueSerializer(new GenericJackson2JsonRedisSerializer());
redisTemplate.setHashValueSerializer(new StringRedisSerializer());
// 设置连接工厂
redisTemplate.setConnectionFactory(connectionFactory);
return redisTemplate;
}
}
方案二 StringRedisTemplate
为了节省内存空间,我们并不会使用JSON序列化器来处理value,而是统一使用String序列化器,要求只能存储String类型的key和value。当需要存储Java对象时,手动完成对象的序列化和反序列化。
Spring默认提供了一个StringRedisTemplate类,它的key和value的序列化方式默认就是String方式。省去了我们自定义RedisTemplate的过程
- 我们可以直接编写一个测试类使用StringRedisTemplate来执行以下方法
@SpringBootTest
class RedisStringTemplateTest {
@Resource
private StringRedisTemplate stringRedisTemplate;
@Test
void testSaveUser() throws JsonProcessingException {
// 1.创建一个Json序列化对象
ObjectMapper objectMapper = new ObjectMapper();
// 2.将要存入的对象通过Json序列化对象转换为字符串
String userJson1 = objectMapper.writeValueAsString(new User("Vz", 21));
// 3.通过StringRedisTemplate将数据存入redis
stringRedisTemplate.opsForValue().set("user:100",userJson1);
// 4.通过key取出value
String userJson2 = stringRedisTemplate.opsForValue().get("user:100");
// 5.由于取出的值是String类型的Json字符串,因此我们需要通过Json序列化对象来转换为java对象
User user = objectMapper.readValue(userJson2, User.class);
// 6.打印结果
System.out.println("user = " + user);
}
}
本文来自博客园,作者:KMP,转载请注明原文链接:https://www.cnblogs.com/touchTomorrow/p/17604533.html