Redis常用数据类型

Redis是NoSQL型数据库,数据都在内存中,支持持久化,支持多种数据结构的存储,如String、list、set、hash、zset。一般作为缓存数据库辅助持久化的数据库。本篇记录基本概念和操作,关于持久化、主从复制、事务、集群等内容的学习查看官方文档。

Redis中文文档

Redis安装配置

Redis安装

  • 下载官网最新redis压缩包,上传到虚拟机中并解压
  • 安装c语言编译环境:yum install gcc
  • 进入redis解压后目录,make进行编译
  • make install
  • 安装目录在/usr/local/bin,包括
    • redis-benchmark:性能测试工具
    • redis-check-aof:修复有问题的AOF文件
    • redis-check-dump:修复有问题的dump.rdb文件
    • redis-sentinel:Redis集群使用
    • redis-server:Redis服务器启动命令
    • redis-cli:客户端操作入口

Redis启动

  • 备份redis.conf到其它目录下,如cp redis.conf /etc/
  • 修改备份文件中daemonize no改为yes,可以让服务在后台启动
  • 启动:redis-server /etc/redis.conf
  • 连接:redis-cli

五大数据类型

Redis默认16个数据库,从0到15,select dbid 可以切换数据库,所有库统一密码。

dbsize:查看当前库的key数量

flushdb:清空当前库

flushall:清空所有库(慎用)

Redis是单线程+多路IO复用技术

String

  • keys *:查看当前库所有key
  • exists key:判断某个key是否存在
  • type key:查看key是什么类型
  • del key:删除指定key的数据
  • unlink key:根据value选择非阻塞删除
  • expire key n:为key设置过期时间,ttl key可以查看过期时间,-1表示永不过期,-2表示已过期
  • set key value:添加键值对
  • get key:查询对应键值
  • append key value:将给定的value追加到原值末尾
  • strlen key:获取值的长度
  • setnx key value:只有key不存在时,设置key值成功
  • incr/decr key:将 key中储存的数字值增1/减1
    • 该操作是原子操作,不会被线程调度机制打断,一旦开始,就一直运行到结束,中间不会切换到另一个线程,Redis单命令的原子性得益于Redis的单线程
  • incrby/decrby key <步长>:将key中存储数值增减步长
  • mset key1 value1 key2 value2 …:同时设置多个key-value
  • mget key1 key2…:同时获取多个value
  • msetnx key1 value1 key2 value2:同时设置多个key-value,当且仅当所有key不存在成功。
    • 原子性:有一个key存在则都设置失败
  • getrange key start end :获取值的范围,两端都闭
  • setrange key offset value:从offset开始,用value覆盖原字符串
  • setex key 过期时间 value:设置键值同时设置过期时间,单位秒
  • getset key value:获取key对应旧值,同时设置新值为value

数据结构:简单动态字符串(Simple Dynamic String,缩写SDS),是可以修改的字符串,内部结构实现上类似于Java的ArrayList,采用预分配冗余空间的方式来减少内存的频繁分配。

如图中所示,内部为当前字符串实际分配的空间capacity一般要高于实际字符串长度len。当字符串长度小于1M时,扩容都是加倍现有的空间,如果超过1M,扩容时一次只会多扩1M的空间。需要注意的是字符串最大长度为512M。

List

  • lpush/rpush key value1 value2…:从左边/右边插入一个/多个值
  • lpop/rpop key:从左边/右边取出一个值。值取完,键也不存在了
  • rpoplpush key1 key2:从key1列表右侧取出一个值,查到key2的左侧
  • lrange key start stop:按照索引下标获得元素(从左到右),0 -1表示所有
  • lindex key index:按照索引下标获取元素
  • llen key:获得列表长度
  • linsert key before/after value newvalue:在value前/后插入newvalue
  • lset key index value:将列表key 下标为index的值替换成value

数据结构:快速链表quickList。在列表元素较少的情况下会使用一块连续的内存存储,这个结构是ziplist,也即是压缩列表。它将所有的元素紧挨着一起存储,分配的是一块连续的内存。当数据量比较多的时候才会改成quicklist。

Redis将链表和ziplist结合起来组成了quicklist。也就是将多个ziplist使用双向指针串起来使用。这样既满足了快速的插入删除性能,又不会出现太大的空间冗余。

Set

  • sadd key value1 value2…:将元素加入集合key中,已存在的元素被忽略
  • smembers key:查询该集合所有值
  • sismember key value:判断集合key是否含有该value值
  • scard key:返回集合元素个数
  • srem key value1 value2…:删除集合中的元素
  • spop key:从集合中随机去除一个值
  • srandmember key n:从集合中随机取出n个值。不会删除
  • smove key1 key2 value:把key1集合的value移到key2中去
  • sinter k1 k2:返回两集合交集
  • sunion k1 k2:返回两集合并集
  • sdiff k1 k2:返回两集合差集,在k1中不在k2中的

数据结构:Set数据结构是dict字典,字典是用哈希表实现的。Java中HashSet的内部实现使用的是HashMap,只不过所有的value都指向同一个对象。Redis的set结构也是一样,它的内部也使用hash结构,所有的value都指向同一个内部值。

Hash

Redis hash是一个String类型的field和value的映射表,适合用于存储对象

  • hset key field value field value…:设置key中的field键为value
    • 如hset user id 1 name jack age 20
  • hget key field:从key中取出键为field的值
  • hdel key field1 field2…:删除key中的field域
  • hexists key field:判断key中是否存在域field
  • hkeys key:列出该key的所有field
  • hvals key:列出该key的所有value
  • hincrby key field increment:为key中field域加上increment
  • hsetnx key field value:将key中域field值设置为value,仅当field域不存在时成功

数据结构:Hash类型对应的数据结构是两种:ziplist(压缩列表),hashtable(哈希表)。当field-value长度较短且个数较少时,使用ziplist,否则使用hashtable。

Zset(有序集合)

与普通集合set非常相似,是一个没有重复元素的字符串集合。不同之处是有序集合的每个成员都关联了一个评分(score),这个评分(score)被用来按照从最低分到最高分的方式排序集合中的成员

  • zadd key score1 value1 score2 value2…:将value值加入有序集合key中,并指定score值
  • zrange key start stop [withscores]:返回有序集合中,下标在[start,stop]之间的元素
  • zrangebyscore key min max:返回有序集 key 中,所有 score 值介于 min 和 max 之间的成员
  • zincrby:为元素加上增量
  • zrem key value:删除该集合指定元素
  • zcount key min max:返回该集合分数区间内元素个数
  • zrank key value:返回该值排名,从0开始

zset结构同时包含一个字典和一个跳跃表,跳跃表按score从小到大保存所有集合元素。字典保存着从member到score的映射。这两种结构通过指针共享相同元素的member和score,不会浪费额外内存。

跳跃表的结构:跳跃表

Jedis操作Redis

依赖

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

连接Redis

1
2
3
4
5
6
7
8
public class JedisDemo {
public static void main(String[] args) {
Jedis jedis = new Jedis("192.168.57.101", 6379);
String pong = jedis.ping();
System.out.println("连接成功:" + pong);
jedis.close();
}
}

Key

1
2
3
4
5
6
7
8
9
10
jedis.set("k1", "v1");
jedis.set("k2", "v2");
Set<String> keys = jedis.keys("*");
System.out.println(keys.size());
for (String key : keys) {
System.out.println(key);
}
System.out.println(jedis.exists("k1"));
System.out.println(jedis.ttl("k1"));
System.out.println(jedis.get("k1"));

String

1
2
jedis.mset("str1","v1","str2","v2","str3","v3");
System.out.println(jedis.mget("str1","str2","str3"));

List

1
2
3
4
5
jedis.lpush("k1","v1","v2");
List<String> list = jedis.lrange("mylist",0,-1);
for (String element : list) {
System.out.println(element);
}

Set

1
2
3
4
5
6
7
jedis.sadd("orders", "order01");
jedis.sadd("orders", "order02");
Set<String> smembers = jedis.smembers("orders");
for (String order : smembers) {
System.out.println(order);
}
jedis.srem("orders", "order02");

Hash

1
2
3
4
5
6
7
8
9
10
11
jedis.hset("hash1","userName","lisi");
System.out.println(jedis.hget("hash1","userName"));
Map<String,String> map = new HashMap<String,String>();
map.put("telphone","13810169999");
map.put("address","atguigu");
map.put("email","abc@163.com");
jedis.hmset("hash2",map);
List<String> result = jedis.hmget("hash2", "telphone","email");
for (String element : result) {
System.out.println(element);
}

Zset

1
2
3
4
5
6
jedis.zadd("zset01", 100d, "z3");
jedis.zadd("zset01", 90d, "l4");
Set<String> zrange = jedis.zrange("zset01", 0, -1);
for (String e : zrange) {
System.out.println(e);
}
Author

叶润繁

Posted on

2022-02-23

Licensed under