Redis概述及使用

本文最后更新于:2 分钟前

本文参考下方方链接整理而成

NoSQL数据库概述

NoSQL(Not Only SQL),不仅仅是SQL,泛指非关系型数据库

NoSQL 不依赖业务逻辑方式存储,而是以简单的key-value模式存储,大大增加了数据库的扩展能力。

适用场景

  1. 对高并发的读写
  2. 海量数据的读写
  3. 对数据高可扩展性的

不适用场景

  1. 需要事务支持
  2. 基于SQL的结构化查询存储,处理复杂的关系,需要即席查询。
  3. 用不着SQL的和用了SQL也不行的情况下,考虑使用NoSQL

常见的三种NoSQL数据库

Memcache

  1. 很早出现的NoSQL数据库
  2. 数据都在内存中,一般不持久化
  3. 支持简单的 key-value模式,支持类型单一
  4. 一般是作为缓存数据库辅助持久化的数据库

Redis

  1. 几乎覆盖了Memcache的绝大部分功能
  2. 数据都在内存中,支持持久化,主要用作备份恢复
  3. 除了支持简单的key-value模式,还支持多种数据结构的存储,比如list、set、hash、zset
  4. 一般是作为缓存数据库辅助持久化的数据库

MongoDB

  1. 高性能、开源、模式自由的文档型数据库
  2. 数据都在内存中,如果内存不足,把不常用的数据保存到硬盘
  3. 虽然是key-value模式,但是对value(尤其是json)提供了丰富的查询功能
  4. 支持二进制数据及大型对象
  5. 可以根据数据的特点替代 RDBMS,成为独立的数据库。或者配合 RDBMS,存储特定的数据

常用五大数据类型

通过键(key)操作的一些命令

  1. keys * 查看当前库所有的key
  2. exists key 判断某个 key 是否存在
  3. type key 查看key 是什么类型
  4. del key 删除指定的key数据
  5. unlink key 根据value选择非阻塞删除,仅将keys从 keyspace 元数据中删除,真正的删除会在后续异步操作
  6. expire key 10 10秒钟:为给定的key设置过期时间
  7. ttl key 查看还有多少秒过期,-1表示永不过期,-2表示已过期
  8. select 命令切换数据库
  9. dbsize 查看当前数据库的key的数量
  10. flushdb 清空当前库
  11. flushall 清空所有库

Redis字符串(String)

String 是二进制安全的。意味着Redis的String可以包含任何数据,比如 jpg图片或者序列化的对象。

String类型是Redis最基本的数据类型,一个Redis中字符串的value最多可以是512M

常用命令:

  1. 添加键值对 set <key> <value>
  2. 查询对应键值 get <key>
  3. 将给定的追加到原值的末尾 append <key> <value>
  4. 获得值的长度 strlen <key>
  5. 只有在 key 不存在时,设置 key 的值 setnx <key> <value>
  6. 将 key 中存储的数字值增加1 ,只能对数字值操作,如果为空,新增值为1 incr <key>
  7. 将 key 中存储的数字值减1,只能对数字值操作,如果为空,新增值为-1 decr <key>
  8. 将 key 中存储的数字值增减,自定义步长 incrby / decrby <key> <步长>
  9. 同时设置一个或多个 key mset <key1><value1><key2><value2>....
  10. 同时获取一个或多个value mget <key1><value1><key2<value2>....
  11. 同时设置一个或多个value,并且仅当所有给定key不存在 msetnx <key1><value1><key2><value2>.... 原子性,有一个失败则都失败
  12. 获得值的范围,类似java中的substring前包,后包 getrange <key> <起始位置><结束位置>
  13. 覆写所储存的字符串值,从<起始位置>开始索引从0开始 setrange <key> <起始位置> <value>
  14. 设置键值的同时,设置过期时间,单位秒 setex <key> <过期时间><value>
  15. 以旧换新,设置了心智同时获得旧值 getset <key> <value>

Redis列表(List)

单键多值

Redis列表是简单的字符串列表,按照插入顺序排序,你可以添加一个元素到列表的头部(左边)或者尾部(右边)。

它的底层时间是个双向链表,对两端的操作性能很高,通过索引下标的操作中间的节点性能会较差。

常用命令:

  1. 从 左边 / 右边插入一个或多个值 lpush rpush <key1><value1><key2><value2>...
  2. 从左边 / 右边吐出一个值 lpop / rpop
  3. 列表右边吐出一个值,插到列表左边 rpoplpush <key1><value1>
  4. 按照索引下标获得元素(从左到右) lrange <key><start><stop>
  5. 0左边第一个,-1右边第一个,(0-1表示获取所有) `lrange mylist 0-1
  6. 按照索引下标获得元素(从左到右) lindex <key><index>
  7. 获得列表长度 llen <key>
  8. 的后面插入插入值 linsert <key> before <value><newvalue>
  9. 从左边删除n个value(从左到右) lrem <key><n><value>
  10. 将列表key下标为index的值替换成valueu lset<key><index><value>

Redis集合(Set)

Redis set对外提供的功能与list类似是一个列表的功能,特殊之处在于set是可以自动排重的,当你需要存储一个列表数据,又不希望出现重复数据时,set是一个很好的选择,并且set提供了判断某个成员是否在一个set集合内的重要接口,这个也是 list所不能提供的。
Redis的set是string类型的无序集合它底层其实是一个value为null的hash表,所以添加,删除,查找的复杂度都是Q(1)
一个算法,随着数据的增加,执行时间的长短,如果是O(1),数据增加,查找数据的时间不变。

常用命令:

  1. 将一个或多个member元素加入到集合key中,已经存在的member元素将被忽略 sadd<key><value1><value2> .....
  2. 取出该集合的所有值。 smembers <key>
  3. 判断集合是否为含有该值,有1,没有0 sismember<key><value>
  4. 返回该集合的元素个数。 scard W<key>
  5. 删除集合中的某个元素。 srem <key><value1><value2>....
  6. 随机从该集合中吐出一个值。vspop <key>
  7. 随机从该集合中取出n个值。不会从集合中删除。 srandmember <key><n>
  8. value把集合中一个值从一个集合移动到另一个集合 smove <source><destination>
  9. 返回两个集合的交集元素。 sinter <key1><key2>
  10. 返回两个集合的并集元素。 vsunion <key1><key2>
  11. 返回两个集合的差集元素(key1中的,不包含key2中的) sdiff <key1><key2>

Redis(Hash)

Redis hash是一个键值对集合。

Redis hash是一个string类型的fieldvalue的映射表,hash特别适合用于存储对象。类似Java里面的Map<String,Object>

常用命令:

  1. 集合中的键赋值hset <key><field><value>
  2. 集合取出 value hget <key1><field>
    批量设置hash 的值 hmset <key1><field1><value1><field2><value2>...
  3. 查看哈希表key中,给定域field是否存在。 hexists <key1><field>
  4. 列出该hash集合的所有field hkeys <key>
  5. 列出该hash集合的所有 valuel hvals <key>
    为哈希表key 中的域field的值加上增量1 -1 hincrby <key>field><increment>
  6. 将哈希表key 中的域field 的值设置为 value,当且仅当域field不存在. hsetnx <key><field><value>

Redis有序集合(Zset)

Redis有序集合zset与普通集合set非常相似,是一个没有重复元素的字符串集合。不同之处是有序集合的每个成员都关联了一个评分( score) ,这个评分 ( score )被用来按照从最低分到最高分的方式排序集合中的成员。集合的成员是唯一的,但是评分可以是重复了
因为元素是有序的,所以你也可以很快的根据评分( score )或者次序( position )来获取一个范围的元素。·
访问有序集合的中间元素也是非常快的,因此你能够使用有序集合作为一个没有重复成员的智能列表。

常用命令:

  1. 将一个或多个member元素及其score值加入到有序集 key当中。 zadd <key><scorei><value1><score2><value2>...
  2. 返回有序集 key 中,下标在之间的元素
    带WITHSCORES,可以让分数一起和值返回到结果集。 zrange <key> <start><stop> [WITHSCORES1]
  3. 返回有序集 key中,所有score值介于min和max 之间(包括等于min或max )的成员。有序集成员按score值递增(从小到大)次序排列。 zrangebyscore key minmax [withscores] [limit offset count]
  4. 同上,改为从大到小排列。zrevrangebyscore key maxmin [withscores] [limit offset count]
  5. 为元素的score加上增量 zincrby <key><increment><value>
  6. 删除该集合下,指定值的元素 zrem <key><value>
    统计该集合,分数区间内的元素个数zrank返回该值在集合中的排名,从О开始。zcount <key><min><max>

配置远程连接Redis

修改redis配置文件

  1. 注掉以下绑定的主机地址

    1
    bind 127.0.0.1
  2. 修改redis的守护进程为no,不启用

    1
    daemonize no 
  3. 修改redis的保护模式为no,不启用

    1
    protected-mode no
  4. 设置 密码

    1
    requirepass
  5. 开放 6379 端口!

  6. 远程连接

使用Jedis操作redis

简单使用

maven依赖

1
2
3
4
5
<dependency>
<groupId>redis.clients</groupId>
<artifactId>jedis</artifactId>
<version>3.6.3</version>
</dependency>

连接使用

1
2
3
4
5
6
7
// 创建jedis对象
Jedis jedis = new Jedis("127.0.0.1", 6379);
// 如果 Redis 服务设置了密码,需要下面这行,没有就不需要
jedis.auth("111");
// 测试
String ping = jedis.ping();
System.out.println(ping);

其他命令和命令行的命令基本一致…… 此处不进行测试

实例:手机验证码

步骤:

  1. 输入手机号,点击发送后随机生成6位数字码,2分钟有效
  2. 输入验证码,点击验证,返回成功或失败
  3. 每个手机号每天只能输入3次

以下是测试类(为了方便,都混合在一个类中了)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
public class PhoneCode {
public static void main(String[] args) {
verifyCode("手机号");
// getRedisCode("手机号","验证码");
}


/**
* 1、生成6位随机数
*
* @return
*/
public static String getCode() {
int i = (int) ((Math.random() * 9 + 1) * 100000);
System.out.println("你的验证码为:" + String.valueOf(i));
return String.valueOf(i);
}

/**
* 2.设置每个手机号每天只能发送3次,存到redis中,并设置过期时间
*
* @param phone
* @param
*/
public static void verifyCode(String phone) {
Jedis jedis = new Jedis("127.0.0.1", 6379);
// 次数
String countKey = "verifyCode" + phone + ":count";
// 验证码
String codeKey = "verifyCode" + phone + ":code";
// 每天发送次数 判断
String count = jedis.get(countKey);
if (StringUtils.isEmpty(count)) {
// 设置发送次数
jedis.setex(countKey, 24 * 60 * 60, "1");
} else if (Integer.parseInt(count) <= 2) {
jedis.incr(countKey);
} else if (Integer.parseInt(count) > 2) {
System.out.println("今日发送次数已达上限!");
return;
}
// 验证码放到 redis中
String code = getCode();
jedis.setex(codeKey, 120, code);
jedis.close();
}

// 效验 是否正确
public static void getRedisCode(String phone, String code) {
Jedis jedis = new Jedis("127.0.0.1", 6379);
String codeKey = "verifyCode" + phone + ":code";
String redisCode = jedis.get(codeKey);
if (redisCode.equals(code)) {
System.out.println("验证成功");
} else {
System.out.println("验证失败");
}
jedis.close();

}
}

SpringBoot整合Redis

maven依赖:

1
2
3
4
5
6
7
8
9
10
11
<!--  redis-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>

<!--commons-pool2-->
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-pool2</artifactId>
</dependency>

yml配置:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
spring:
redis:
host: 127.0.0.1
port: 6379
database: 0
# 连接超时时间(毫秒)
timeout: 18000000
lettuce:
pool:
# 连接池最大连接数(使用负值表示没有限制)
max-active: 20
# 最大阻塞等待时间(使用负值表示没有限制)
max-wait: -1
# 连接池中最大空闲连接
max-idle: 5
# 连接池中最小空闲连接
min-idle: 0

配置类

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
@Configuration
public class RedisConfig {
// 自己定义了一个 RedisTemplate
@Bean
public RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory
factory) {
// 我们为了自己开发方便,一般直接使用 <String, Object>
RedisTemplate<String, Object> template = new RedisTemplate<String, Object>();
template.setConnectionFactory(factory);
// Json序列化配置
Jackson2JsonRedisSerializer jackson2JsonRedisSerializer = new
Jackson2JsonRedisSerializer(Object.class);
ObjectMapper om = new ObjectMapper();
om.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
om.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL);
jackson2JsonRedisSerializer.setObjectMapper(om);
// String 的序列化
StringRedisSerializer stringRedisSerializer = new StringRedisSerializer();
// key采用String的序列化方式
template.setKeySerializer(stringRedisSerializer);
// hash的key也采用String的序列化方式
template.setHashKeySerializer(stringRedisSerializer);
// value序列化方式采用jackson
template.setValueSerializer(jackson2JsonRedisSerializer);
// hash的value序列化方式采用jackson
template.setHashValueSerializer(jackson2JsonRedisSerializer);
template.afterPropertiesSet();
return template;
}
}

完成!

Redis事务

Redis事务是一个单独的隔离操作∶事务中的所有命令都会序列化、按顺序地执行。事务在执行的过程中,不会被其他客户端发送来的命令请求所打断。。
Redis事务的主要作用就是串联多个命令防止别的命令插队。

Multi、Exec、discard

从输入Multi命令开始,输入的命令都会依次进入命令队列中,但不会执行,直到输入Exec后,Redis 会将之前的命令队列中的命令依次执行。
组队的过程中可以通过discard来放弃组队。

例子:

正常执行

1
2
3
4
5
6
7
8
9
10
127.0.0.1:6379> multi
OK
127.0.0.1:6379(TX)> set k1 value1
QUEUED
127.0.0.1:6379(TX)> set k2 value2
QUEUED
127.0.0.1:6379(TX)> exec
1) OK
2) OK
127.0.0.1:6379>

取消组队

1
2
3
4
5
6
7
8
9
127.0.0.1:6379> multi
OK
127.0.0.1:6379(TX)> set k1 value1
QUEUED
127.0.0.1:6379(TX)> set k2 value2
QUEUED
127.0.0.1:6379(TX)> discard
OK
127.0.0.1:6379>

事务的错误处理

组队中某个命令出现了报告错误,执行时整个的所有队列都会被取消

如果执行阶段某个命令报出了错误,则只有报错的命令不会被执行,而其他的命令都会执行,不会回滚

未完结…….

时间不定…….


本文作者: 仅安
本文链接: https://jinan6.vip/posts/2395204792/
版权声明: 本博客所有文章除特别声明外,均采用 CC BY-SA 4.0 协议 ,转载请注明出处!