题记
本文涵盖了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">
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">
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
// 设置连接工厂
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);
}