Redis
Redis 是一个基于内存的键值数据库
安装
Window下Redis的安装和部署详细图文教程(Redis的安装和可视化工具的使用)_redis安装_明金同学的博客-CSDN博客
出现上面代表安装成功了
redis 一共有 16 个库
安装后 再安装图形化界面
图形界面十分方便去使用
redis数据结构介绍
redis 是 键值对的数据库 key 一般是 string 类型 但是 value 的类型 多种多样
String 类型
- set 添加或者修改一个已经存在的String类型的键值对
- get 获取到对应 key 的 value
- mset 批量添加多个 String 类型的 键值对
- mget 获取到所有 key 的 value
- incr 让一个整型的 key 自增 1
- incrby 让一个整型的 key 自增 并且指定 步长
- incrbyfloat 让一个 浮点 类型 的数字自增并且指定步长
- setnx 添加一个String 类型的 键值对 前提时 这个 key 不存在 否则不执行
- setex 添加一个 String 类型的键值对 并且指定有效期
key 的结构
redis 的 key 允许 有多个 单词 形成 层级结构 多个单词之间 用 : 隔开
Hash 类型
类似于 java 中的 HashMap 结构 Hash 结构 可以将对象中的 每个 字段 独立存储 可以针对 单个字段做 CRUD
- hset key field value 添加或者修改 hash 类型 key 的 field 的值
- hset key field 获取一个hash类型key 的 field 的值
- hmset 批量添加多个 hash 类型 key 的 field 的值
- hmget 批量获取 多个 hash 类型 key 中的 所有 field 和 value
- hgetall 获取一个hash类型的key中的所有的field 和 value
- hkeys 获取一个hash 类型 key 中 所有的 field
- hvals 获取一个hash 类型 的 key 中的 所有的 value
- hincrby 让一个hash 类型 key 字段值 自增 并 指定步长
- hsetnx 添加一个 hash 类型的 key 的 field 值 前提是这个 field 不存在 否则不执行
List 类型
redis 中 的 list 类型 与 java 中的 LinkedList 类似 可以看作 是一个 双向链表 结构 既可以支持 正向检索 也可以 支持 反向 检索
特征也与 LinkedList 类似
- 有序
- 元素可以重复
- 插入和删除快
- 查询速度一般
- lpush 向 列表 左侧 插入 一个 或者 多个 元素
- lpop 移除 并 返回 列表 左侧 第一个元素 没有则返回 nil
- rpush 向 列表 右侧 插入 一个或者多个 元素
- rpop 移除 并且 返回 列表 右侧 的 第一个元素
- lrange 返回一段 下标 范围 内 的 所有 元素
- blpop 和 brpop 与 lpop 和 rpop 类似 只不过 在 没有 元素 时 等待 指定时间 而不是直接 返回 nil
Set 类型
redis 的 set 结构 与 java 中的 HashSet 类似 可以看作 是一个 value 为 null 的 HashMap
- 无序
- 元素 不可 重复
- 查找快
- 支持交集 并集 差集 等 功能
- sadd 向 set 中 添加 一个多个元素
- srem 移除 set 中的指定元素
- scard 返回 set 中元素的个数
- sismemery 判断 一个元素 是否存在 于 set 中
- smemers 获取 set 中 所有 元素
- sinter 求 集合 的 交集
- sdiff 求 集合 的 差集
- sunion 求 集合 的并集
SortedSet 类型
redis 中的 SortedSet 是一个可排序 的 set 集合 与 java 中的 TreeSet 有些类似 但是底层 数据结构 却 差别 很大 SortedSet 中 每一个元素 都 带有 一个 score 属性 , 可以基于 score 属性 对元素 排序 。底层 的 实现 是一个 跳表 加 hash 表
- 可排序
- 元素 不重复
- 查询速度快
- zadd 添加 一个 或 多个元素 到 sortedset 中 如果已经存在 则 更新其 score 值
- zrem 删除 sortedset 中的一个指定元素
- zcore 获取 sortedset 中 指定 元素 的score值
- zrank 获取 sortedset 中的元素个数
- zcard 获取 sortedset 中元素个数
- zcount 统计score 值在给定范围 内 所有 元素 的个数
- zincrby 让sortedset 的指定元素自增 步长 为指定的 increment 值
- zrange 按照score排序后 获取指定排名 范围内的元素
- zrangebyscore 按照 score 排序后 获取指定 score 范围内 的 元素
- zdiff zinter zunion 求差集 交集 并集
默认排名 都是 升序 如果还想要降序 在命令的后面 添加 rev 即可
GEO 类型
BitMap 类型
HyperLog 类型
Redis 通用命令
- keys 查看符合模板的所有key 不建议在生产环境使用
- del 删除一个指定的key
- exists 判断该 key 是否存在
- expire 设置一个key的有效期 有效期到了后key会自动删除 单位是秒
- TTL 查看一个key的剩余有效期 当TTL为 -1 时 说明该 数据 永久有效期 为 -2 时表示已经过期
Jedis 的 使用
Jedis 是 redis 在java语言上的 客户端
Java guide | Redis
使用:
新建maven项目
依赖:
<dependency>
<groupId>redis.clients</groupId>
<artifactId>jedis</artifactId>
<version>4.3.1</version>
</dependency>
测试代码:
package com.lxh;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import redis.clients.jedis.Jedis;
public class JedisTest {
private Jedis jedis;
@BeforeEach
void setUp()
{
//建立连接
jedis=new Jedis("127.0.0.1",6379);
// 如果你有设置密码 就要加下面这句话 我是并没有 设置密码的
// jedis.auth("123456");
jedis.select(0);
}
@Test
void testString ()
{
String result=jedis.set("name","李泽言");
System.out.println("result ="+result);
String name = jedis.get("name");
System.out.println("name="+name);
}
@AfterEach
void tearDown()
{
if (jedis!=null)
{
jedis.close();
}
}
}
Jedis 连接池
Jedis 本身 是 线程 不安全 的 ,并且 频繁 的 创建 和 销毁 会有性能损耗 因此 我们推荐大家 使用 Jedis 连接池 代替 Jedis 的 直连 方式
代码:
package com.lxh;
import redis.clients.jedis.Jedis;
import redis.clients.jedis.JedisClientConfig;
import redis.clients.jedis.JedisPool;
import redis.clients.jedis.JedisPoolConfig;
public class JedisConnectionFactory {
private static JedisPool jedisPool = new JedisPool();
static {
JedisPoolConfig jedisPoolConfig=new JedisPoolConfig();
//设置最大连接数
jedisPoolConfig.setMaxTotal(8);
//设置最大空闲数
jedisPoolConfig.setMaxIdle(8);
//设置最小空间数
jedisPoolConfig.setMinIdle(0);
jedisPool = new JedisPool(jedisPoolConfig,"127.0.0.1",6379,1000);
}
public static Jedis getJedis(){
return jedisPool.getResource();
}
}
运行结果:
SpringDataRedis
SpringDataRedis 是 Spring 中数据 操作 的 模块 包含 各种 对 数据库 的 集成 其中对 Redis 的集成 模块 就叫做 SpringDataRedis
Spring Data Redis
- 提供了对不同 Redis 客户端的整合
- 提供了 RedisTemplate 统一 API 来操作 Redis
- 支持 Redis 的发布 订阅 模型
- 支持 Redis 哨兵 和 Redis 集群
- 支持 基于 Lettuce 的响应式编程
- 支持 基于 JDK JSON 字符串 Spring 对象 的数据 序列化 及 反序列化
- 支持基于 Redis 的 JDKCollection 实现
SpringDataRedis 中提供了 对 RedisTamplate 工具类 其中封装了 对各种 Redis 的操作 并且将不同数据类型 的 操作 API 封装到了 不同的类中
SpringDataRedis 使用步骤
新建一个 基于 maven 的 spring 的项目
引入 spring-boot-starter-data-redis 依赖
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>3.1.4</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>com.example</groupId>
<artifactId>redisData-demo</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>redisData-demo</name>
<description>redisData-demo</description>
<properties>
<java.version>17</java.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
<version>3.0.4</version>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.26</version>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<version>3.1.0</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-pool2</artifactId>
<version>2.11.1</version>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<version>3.1.4</version>
<configuration>
<excludes>
<exclude>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</exclude>
</excludes>
</configuration>
</plugin>
</plugins>
</build>
</project>
在 application.properties 下 写入这些
#这里是地址 localhost 对应 的 就是 127.0.0.1
spring.data.redis.host=localhost
#这里是端口号
spring.data.redis.port=6379
#如果你需要设置密码,就写这个 否则就不写
#spring.data.redis.password=12345
#当前使用的是哪一个 数据库 一共 是 下标 0 - 15
spring.data.redis.database=1
#是否使用线程池
spring.data.redis.lettuce.pool.enabled=true
#最大活动线程池个数
spring.data.redis.lettuce.pool.max-active=8
#最长等待时间 以毫秒 为单位
spring.data.redis.lettuce.pool.max-wait=2000
#这是最大 空闲 连接池 个数
spring.data.redis.lettuce.pool.max-idle=8
然后就是测试
package com.example.redisdatademo;
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 RedisDataDemoApplicationTests {
@Autowired
private RedisTemplate redisTemplate;
@Test
void contextLoads() {
}
@Test
void testString()
{
//写入一条 String 数据
redisTemplate.opsForValue().set("user","lizeyan");
String user = (String) redisTemplate.opsForValue().get("user");
System.out.println("user : "+user);
}
}
运行 testString 能正确输出即可
SpringDataRedis 的 序列化方式
RedisTemplate 可以 接收任意 Object 作为 值 写入Redis 只不过 写入前会把Object序列化 为字节形式 默认是采用JDK序列化的 ,得到的结构就会变成 这样
缺点 可读性差,内存占用大
我们可以重写方法 来修改 存入 redis 的数据状态
package com.example.redisdatademo;
import com.fasterxml.jackson.annotation.JsonAutoDetect;
import com.fasterxml.jackson.annotation.PropertyAccessor;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.serializer.GenericJackson2JsonRedisSerializer;
import org.springframework.data.redis.serializer.Jackson2JsonRedisSerializer;
import org.springframework.data.redis.serializer.RedisSerializer;
import org.springframework.data.redis.serializer.StringRedisSerializer;
import java.net.UnknownHostException;
@Configuration
public class redisDataConfig {
@Bean
public RedisTemplate<String,Object> redisTemplate(RedisConnectionFactory redisConnectionFactory) throws UnknownHostException
{
RedisTemplate<String, Object> redisTemplate = new RedisTemplate<>();
redisTemplate.setConnectionFactory(redisConnectionFactory);
// 设置key和hashKey的序列化器为String类型
redisTemplate.setKeySerializer(new StringRedisSerializer());
redisTemplate.setHashKeySerializer(new StringRedisSerializer());
// 设置value和hashValue的序列化器为Jackson2JsonRedisSerializer
Jackson2JsonRedisSerializer<Object> jsonRedisSerializer = new Jackson2JsonRedisSerializer<>(Object.class);
ObjectMapper objectMapper = new ObjectMapper();
objectMapper.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
objectMapper.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL);
jsonRedisSerializer.setObjectMapper(objectMapper);
redisTemplate.setValueSerializer(jsonRedisSerializer);
redisTemplate.setHashValueSerializer(jsonRedisSerializer);
redisTemplate.afterPropertiesSet();
return redisTemplate;
//
// //创建 Template
// RedisTemplate<String,Object> redisTemplate=new RedisTemplate<>();
// //设置连接工厂
// redisTemplate.setConnectionFactory(redisConnectionFactory);
// //设置序列化工具
// GenericJackson2JsonRedisSerializer jsonRedisSerializer=new GenericJackson2JsonRedisSerializer();
//
// //key 和 hashKey 采用 string 序列化
// redisTemplate.setKeySerializer(RedisSerializer.string());
// redisTemplate.setHashKeySerializer(RedisSerializer.string());
//
// //value 和 hashValue 采用 string 序列化
// redisTemplate.setValueSerializer(RedisSerializer.string());
// redisTemplate.setHashValueSerializer(RedisSerializer.string());
//
// return redisTemplate;
}
}
要导入依赖
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>2.15.1</version>
</dependency>
测试输出
如果按照上面这个方式 那么会需要额外的存储空间来存储 这个类的路径 为了节省 内存空间 我们并不会 使用 JSON 序列化 来处理 value 而是 使用 String 序列化 器 。要求 只能存储 String 类型的 key 和 value ,当需要 存储 java 对象 时 手动 完成对象 的序列化 和 反序列化。
Spring 默认提供了一个 StringRedisTemplate 类 它的 key 和 value 的序列化方式 默认就是String 方式 省去了 我们自定义 RedisTemplate 的过程
package com.example.redisdatademo;
import com.example.bean.User;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
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;
@SpringBootTest
class RedisDataDemoApplicationTests {
@Autowired
private RedisTemplate<String, Object> redisTemplate;
@Autowired
private StringRedisTemplate stringRedisTemplate;
//JSON工具
private static final ObjectMapper mapper=new ObjectMapper();
@Test
void contextLoads() {
}
@Test
void testString()
{
//写入一条 String 数据
redisTemplate.opsForValue().set("user","lizeyan");
String user =(String) redisTemplate.opsForValue().get("user");
System.out.println("user : "+user);
}
@Test
void testObject()
{
redisTemplate.opsForValue().set("user:xm",new User("许墨",26));
User newUser=(User) redisTemplate.opsForValue().get("user:xm");
System.out.println(newUser);
}
@Test
void testStringTemplate() throws JsonProcessingException {
//准备对象
User user=new User("helios",22);
//手动序列化
String json=mapper.writeValueAsString(user);
//写入一条数据到 redis
stringRedisTemplate.opsForValue().set("user:zql",json);
//读取数据
String val=stringRedisTemplate.opsForValue().get("user:zql");
//反序列化
User newUser=mapper.readValue(val,User.class);
System.out.println("user : "+newUser);
}
}
运行 testStringTemplate 就可以了 我们可以发现这个是没有类的路径的