Redis专题

Redis专题

题记

本文涵盖了Redis的各种数据结构和命令,Redis的各种常见Java客户端的应用和最佳实践

jedis案例github地址:https://github.com/whltaoin/fedis_java_demo

SpringbootDataRedis案例github地址:https://github.com/whltaoin/springbootDataRedis_demo

一、初始RedisSQL与NoSQL对比结构化(Structured)对比 SQL具有严格的结构化格式(左图)NoSQL的数据存储格式相对随意(右图)关系对比 SQL在表和表间**可能存在联系**,在操作一张表时,需要考虑对应关联表的完整性。代码语言:javascript复制2. NoSQL数据间是**无关联**的,(下图为存储方式)查询对比 SQL查询有**固定的语法**,只要是SQL都可以使用相同的语句查询。代码语言:javascript复制2. NoSQL没有固定的语法,每个NoSQL都有自己的语法糖(下图为查询同一个东西,出现了不同的语法)SQL需要满足**事务的ACID特性**(原子性、一致性、隔离性、持久性)NoSQL只是**基本满足事务的ACID**差异总结:初始Redis简介Redis(远程词典服务器),是一个基于内存的**键值型NoSQL**数据库

特征: 键值型:key-value单线程:命令具有原子性低延迟、数据块原因:(基于**内存**、IO多路复用、良好的编码)支持数据持久化支持主从集群(主服务器和副服务器)、分片集群(将数据拆分,分别存在不同的服务器上)支持多语言客户端(java、C…)安装Redis(Linux安装)忽略…

二、Redis常见命令数据类型介绍String

1.Hash 哈希表List 有序集合,本质是链表Set 无序集合,不可重复SortedSet 有序集合,不可重复GEO 地理坐标通用命令查询所有通用命令:代码语言:javascript复制help @generic查看符合模版的所有key 注意:不建议在生产环境设备上使用该命令,因为模糊查询,效率不高且浪费资源。代码语言:javascript复制# 语法

keys +[pattern]删除key 可以单个删除,也可以多个一起删除代码语言:javascript复制del [key]删除一个或多个示例

判断key是否存在 可以判断单个,也可以判断多个代码语言:javascript复制exists [key]判断单个和多个示例

给key设置有效期,到期后自动删除(单位秒) TTL查看可以的有效时间代码语言:javascript复制expire [key] [seconds]

ttl key示例:设置age1的有效期为10s,到期后自动删除

总结String类型setgetmsetmgetincrincrbyincrbyfloatsetnx(新增,存在则不创建) 等价于:set [key value] nxsetex 等价于:setKey的层级格式思考:解决方法示例代码语言:javascript复制heima:user:1

herma:product:1层级结构:

Hash类型Hash类型(散列),其中的value是一个**无序字典** 类似于java 中的HashMap结构使用场景: 当要修改JSON数据中某个属性的值时,使用String存储的需要重新覆盖数据,而我们的需求只是**想要修改某个值**常用命令示例 hset代码语言:javascript复制2. hget代码语言:javascript复制3. hmset代码语言:javascript复制4. hmget代码语言:javascript复制5. hgetall代码语言:javascript复制6. hkeys代码语言:javascript复制7. hvals 代码语言:javascript复制8. hincrby代码语言:javascript复制9. hsetnx(已存在,不新建)List类型Redis中的List类型于java中的LinkedList类似,可以当它是一个双向链表结构。 既可以支持正向检索也可以支持反向检索。特征: 有序元素可重复插入和删除快查询速度一般使用场景举例: 朋友圈点赞列表,评论列表等常用命令:代码语言:javascript复制1. 示例:Set类型Redis的Set结构和Java中的HashSet类似,可以看做一个value为null的HashMap。特征: 无序元素不可重复查找快支持交集、并集、差集等功能单个set常见命令代码语言:javascript复制1. 示例多个set操作命令 求交集(sinter):两集合公共的代码语言:javascript复制2. 求并集(sunion):所有元素合并代码语言:javascript复制3. 求差集(sdiff):set中有,但是set2中没有练习题:代码语言:javascript复制1. 张三的好友人数代码语言:javascript复制2. 张三和李四的共同好友代码语言:javascript复制3. 查询那些人是张三的好友但是不是李四的好友代码语言:javascript复制4. 查询张三和李四的共同好友代码语言:javascript复制5. 判断李四是否是张三的好友代码语言:javascript复制6. 判断张三是否是李四的好友代码语言:javascript复制7. 将李四从张三的好友列表中移除SortedSet类型特性: 可排序元素不可重复查询快应用场景: 因为可排序,常用于实现**排行榜**功能常用命令练习题:代码语言:javascript复制1. 添加数据代码语言:javascript复制2. 删除Tom代码语言:javascript复制3. 获取Amy分数代码语言:javascript复制4. 获取Rose排名代码语言:javascript复制5. 查询80分以上人数代码语言:javascript复制6. 给Amy加2分代码语言:javascript复制7. 查询排名前三的同学代码语言:javascript复制8. 查询80以下的同学三、Redis的Java客户端常用Java客户端的优缺点对比Jedis使用(单线程) github地址:https://github.com/whltaoin/fedis_java_demo

使用Jedis分为了四步骤: 导入依赖初始化Jedis对象执行Jedis中的操作方法释放Jedis对象具体实现 导入依赖代码语言:javascript复制

xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"

xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">

4.0.0

org.example

jedis-test

1.0-SNAPSHOT

17

17

UTF-8

redis.clients

jedis

6.0.0

junit

junit

4.13.2

test

代码语言:javascript复制b. 测试类方法内容代码语言:javascript复制package cn.varin;

import org.junit.After;

import org.junit.Before;

import org.junit.Test;

import redis.clients.jedis.Jedis;

public class JedisTest {

private Jedis jedis;

@Before

public void init(){

jedis = new Jedis("ip",6379);

jedis.auth("密码");

jedis.select(0);

}

@Test

public void StringTest(){

String set = jedis.set("name", "varin");

System.out.println("执行set后结果为:"+set);

String name = jedis.get("name");

System.out.println("key为name的value为:"+name);

}

@After

public void close(){

if(jedis !=null){

jedis.close();

}

}

}代码语言:javascript复制3. 执行结果Jedis使用(使用连接池) github地址:https://github.com/whltaoin/fedis_java_demo

使用步骤: 创建连接池获取Jedis对象操作Jedis对象归还连接池对象具体代码 创建连接池对象代码语言:javascript复制package cn.varin.jedis.utils;

import redis.clients.jedis.Jedis;

import redis.clients.jedis.JedisPool;

import redis.clients.jedis.JedisPoolConfig;

// Jedis连接池对象

public class JedisConnectionFactory {

//

static public final JedisPool jedisPool;

static {

// 创建配置

JedisPoolConfig jedisPoolConfig = new JedisPoolConfig();

// 最大连接数

jedisPoolConfig.setMaxTotal(10);

// 最大空闲数

jedisPoolConfig.setMaxIdle(10);

// 最小空闲数

jedisPoolConfig.setMinIdle(2);

// 空闲等待时间

jedisPoolConfig.setMaxWaitMillis(1000);

jedisPool = new JedisPool(jedisPoolConfig,"host",6379,100,"password");

}

public static Jedis getResource(){

return jedisPool.getResource();

}

}代码语言:javascript复制2. 测试类代码代码语言:javascript复制package cn.varin;

import cn.varin.jedis.utils.JedisConnectionFactory;

import org.junit.After;

import org.junit.Before;

import org.junit.Test;

import redis.clients.jedis.Jedis;

public class JedisTest {

private Jedis jedis;

@Before

public void init(){

jedis = JedisConnectionFactory.getResource();

jedis.select(0);

}

@Test

public void StringTest(){

String set = jedis.set("name", "varya");

System.out.println("执行set后结果为:"+set);

String name = jedis.get("name");

System.out.println("key为name的value为:"+name);

}

@After

public void close(){

if(jedis !=null){

jedis.close();

}

}

}代码语言:javascript复制3. 执行结果:SpringDataRedis使用 github示例案例地址:https://github.com/whltaoin/springbootDataRedis_demo

springData介绍项目地址:https://spring.io/projects/spring-data-redis#learnRedis模版版本信息SpringDataRedis快速入门SpringbootDataRedis使用步骤基本示例导入依赖代码语言:javascript复制

xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">

4.0.0

org.springframework.boot

spring-boot-starter-parent

3.4.5

cn.varin

springbootDataRedis_demo

0.0.1-SNAPSHOT

springbootDataRedis_demo

springbootDataRedis_demo

17

org.springframework.boot

spring-boot-starter-data-redis

org.apache.commons

commons-pool2

org.springframework.boot

spring-boot-starter-web

org.projectlombok

lombok

true

org.springframework.boot

spring-boot-starter-test

test

org.apache.maven.plugins

maven-compiler-plugin

org.projectlombok

lombok

org.springframework.boot

spring-boot-maven-plugin

org.projectlombok

lombok

配置yml代码语言:javascript复制spring:

data:

redis:

port: 6379

password: password

database: 0

lettuce:

pool:

max-active: 10

max-idle: 10

min-idle: 0

max-wait: 100ms

host: address编写测试类代码语言:javascript复制package cn.varin.springbootdataredis_demo;

import cn.varin.springbootdataredis_demo.pojo.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.ValueOperations;

@SpringBootTest

class SpringbootDataRedisDemoApplicationTests {

@Autowired

RedisTemplate redisTemplate;

@Test

void setTest() {

ValueOperations valueOperations = redisTemplate.opsForValue();

valueOperations.set("user:1",new User("varin",1).toString());

Object o = valueOperations.get("user:1");

System.out.println(o);

}

}结果:重构redisTemplate序列化和反序列化工具问题代码语言:javascript复制1. 在我们直接使用redisTemplate时,存入到redis的内容,是经过编译的字节,

2. 影响阅读性

3. 增加了存储空间解决方案: 自定义序列化和反序列话的编码格式步骤 建立template设置连接工厂设置序列化工具分别对key和value设置不同的格式代码语言:javascript复制package cn.varin.springbootdataredis_demo.config;

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.RedisSerializer;

@Configuration

public class RedisTamplateConfig {

@Bean

public RedisTemplate redisTemplate(RedisConnectionFactory factory){

RedisTemplate template = new RedisTemplate<>();

// 设置连接工厂

template.setConnectionFactory(factory);

// 创建序列化工具

GenericJackson2JsonRedisSerializer genericJackson2JsonRedisSerializer = new GenericJackson2JsonRedisSerializer();

// 对key

template.setKeySerializer(RedisSerializer.string());

template.setHashKeySerializer(RedisSerializer.string());

// 对value

template.setValueSerializer(genericJackson2JsonRedisSerializer);

template.setHashValueSerializer(genericJackson2JsonRedisSerializer);

return template;

}

}测试类

代码语言:javascript复制package cn.varin.springbootdataredis_demo;

import cn.varin.springbootdataredis_demo.pojo.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.ValueOperations;

@SpringBootTest

class SpringbootDataRedisDemoApplicationTests {

@Autowired

RedisTemplate redisTemplate;

@Test

void setTest() {

ValueOperations valueOperations = redisTemplate.opsForValue();

// value为user对象

valueOperations.set("user:2",new User("varin",1));

Object o = valueOperations.get("user:1");

System.out.println(o);

}

}测试结果StringRedisTamplate类使用问题: 虽然自定义序列化工具可以解决上一问题,但是修改后在JSON字符串中会多存储一个类的包名 导致增大存储的空间解决方法, 使用StringRedisTamplate类,在加上自己使用第三方的序列化工具进行存储。 优点:在存储时不会增加额外的数据缺点:增加少许的代码量示例代码代码语言:javascript复制@Autowired

StringRedisTemplate stringRedisTemplate;

// 用于转Json格式

private static final ObjectMapper mapper = new ObjectMapper();

@Test

void StringRedisTamplateTest() throws JsonProcessingException {

User user = new User("varya",1);

// 转JSON格式

String s = mapper.writeValueAsString(user);

// 写入数据

stringRedisTemplate.opsForValue().set("user:3",s);

// 读取数据

String s1 = stringRedisTemplate.opsForValue().get("user:3");

// 反序列化

User user1 = mapper.readValue(s1, User.class);

System.out.println(user1);

}

相关文章