In-depth understanding of Redis (2) Redis data types and operations

1. Redis data type

The reason why Redis is single-threaded fast

High-performance servers are not necessarily multi-threaded.
Multi-threaded CPUs will switch context, which is time-consuming.
CPU-memory-hard disk speed is slower.
Core: Redis puts all data in memory, single-threaded operation efficiency is very high, memory system, without up and down switching efficiency is the highest.
Redis official website address
redis command reference

Redis-key

  • Redis's redisObject structure
typedef struct redisObject {
	unsigned type:4; 		// 类型
	unsigned encoding:4; 	// 编码
	unsigned lru:LRU_BITS;
	int refcount;
	void *ptr;				// 指向底层实现数据结构的指针
} robj;

encoding records the encoding used by the formation, that is, the data structure used at the bottom of the object. We store the key-value key-value pair and do not specify the encoding of the object. Redis will set different encodings according to different scenarios.

Coding constantEncoding corresponds to the underlying data structureOBJECT_ENCODING command output
REDIS_ENCODING_INTlong type integerint
REDIS_ENCODING_EMBSTRSimple dynamic string encoded by embstrembstr
REDIS_ENCODING_RAWSimple dynamic stringraw
REDIS_ENCODING_HTdictionaryhashtable
REDIS_ENCODING_LINKEDLISTDouble-ended linked listlinkedlist
REDIS_ENCODING_ZIPLISTCompressed listziplist
REDIS_ENCODING_INTSETInteger setintset
REDIS_ENCODING_SKIPLISTSkip list and dictionaryskiplist

1.1 String

data structure:

struct sdshdr{
	int len;
	int free;
	char buf[];
}

Commonly used commands:

127.0.0.1:6379> set key v1 # 设置值
OK
127.0.0.1:6379> get key # 获得值
"v1"
127.0.0.1:6379> keys * # 所有的 key
"key"
127.0.0.1:6379> exists key # 判断某个 key 是否存在
(integer) 1
127.0.0.1:6379> append key va2 # 追加字符串,如果不存在,相当于 setkey
(integer) 5
127.0.0.1:6379> get key
"v1va2"
127.0.0.1:6379> append key "key1"
(integer) 9
127.0.0.1:6379> get key
"v1va2key1"
127.0.0.1:6379> strlen key # 获取字符串长度
(integer) 9
127.0.0.1:6379> append key ,,,
(integer) 12
127.0.0.1:6379> get key
"v1va2key1,,,"
127.0.0.1:6379> strlen key
(integer) 12
127.0.0.1:6379> append name zhangsan
(integer) 8
127.0.0.1:6379> get name
"zhangsan"
###########################################
#		i ++
127.0.0.1:6379> set views 0
OK
127.0.0.1:6379> type views
string
127.0.0.1:6379> get views
"0"
127.0.0.1:6379> incr views # 增加 1
(integer) 1
127.0.0.1:6379> incr views
(integer) 2
127.0.0.1:6379> get views
"2"
127.0.0.1:6379> decr views # 减少 1
(integer) 1
127.0.0.1:6379> get views
"1"
127.0.0.1:6379> incrby views 10 # 增加 10
(integer) 11
127.0.0.1:6379> get views
"11"
127.0.0.1:6379> decrby views 5 # 减少 5
(integer) 6
127.0.0.1:6379> get views
"6"
###########################################
#			字符串范围
127.0.0.1:6379> keys *
1) "key"
127.0.0.1:6379> set key "hello,word" # 设置字符串
OK
127.0.0.1:6379> get key
"hello,word"
127.0.0.1:6379> getrange key 0 3 # 截取字符串 [0,3]
"hell"
127.0.0.1:6379> getrange key 0 -1 # 截取全部字符串,相当于 get key
"hello,word"
#			替换字符串
127.0.0.1:6379> set key1 abdfsa
OK
127.0.0.1:6379> get key1
"abdfsa"
127.0.0.1:6379> setrange key1 1 sss # 替换指定位置开始字符串
(integer) 6
127.0.0.1:6379> getrange key1 0 -1
"assssa"
###########################################
# setex (set with expire)	# 设置过期时间
# setnx (set if not exist)	# 不存在再设置 (在分布式锁中使用)
127.0.0.1:6379> setex key2 30 "hello" # 设置 key2 的值为 hello 30秒后过期
OK
127.0.0.1:6379> ttl key3
(integer) -2
127.0.0.1:6379> setex key2 30 "hello"
OK
127.0.0.1:6379> ttl key2
(integer) 25
127.0.0.1:6379> setnx mykey "redis" # 如果 mykey 不存在,创建 mykey
(integer) 1
127.0.0.1:6379> keys *
1) "key2"
2) "key1"
3) "key"
4) "mykey"
127.0.0.1:6379> ttl key2
(integer) 1
127.0.0.1:6379> keys *
1) "key1"
2) "key"
3) "mykey"
127.0.0.1:6379> setnx mykey "MongoDB" # 如果 mykey 存在,创建失败!
(integer) 0
127.0.0.1:6379> get mykey
"redis"
###########################################
# mset
# mget
127.0.0.1:6379> mset k1 v1 k2 v2 k3 v3 # 同时设置多个值
OK
127.0.0.1:6379> keys *
1) "k3"
2) "k2"
3) "k1"
127.0.0.1:6379> mget k1 k2 k3 # 同时获取多个值
1) "v1"
2) "v2"
3) "v3"
127.0.0.1:6379> msetnx k1 v1 k4 v4 # msetnx 是一个 原子性操作!
(integer) 0
127.0.0.1:6379> get k4
(nil)

# 对象
set user:1 {name:zhangsan,age:3} # 设置一个 user:1 对象,值为 json 字符来保存一个对象

# 这里的 key 为 user:{id}:{name}
127.0.0.1:6379> mset user:1:name zhangsan user:1:age 2
OK
127.0.0.1:6379> mget user:1:name user:1:age
1) "zhangsan"
2) "2"

###########################################

# getset # 先 get 再 set

127.0.0.1:6379> getset db redis # 如果不存在,返回 nil
(nil)
127.0.0.1:6379> get db
"redis"
127.0.0.1:6379> getset db MongoDB # 如果存在值,获取原来的值,设置新的值。
"redis"
127.0.0.1:6379> get db
"MongoDB"

Application scenarios:

Ordinary key/value storage.
Count the number of multiple units, the number of
fans, the
distributed lock
counter, the
distributed session
object cache

1.2 List

The list can be used as a stack, a queue, or a blocking queue!
The list command has started with l.
Commonly used commands:

###########################################
127.0.0.1:6379> lpush list one # 头插法,将一个或多个值插入列表头部
(integer) 1
127.0.0.1:6379> lpush list tow
(integer) 2
127.0.0.1:6379> lpush list three
(integer) 3
127.0.0.1:6379> lrange list 0 -1 # 获取 list 中的值
1) "three"
2) "tow"
3) "one"
127.0.0.1:6379> rpush list four # 尾插法,将一个或多个值插入到列表尾部
(integer) 4
127.0.0.1:6379> lrange list 0 -1
1) "three"
2) "tow"
3) "one"
4) "four"
###########################################
# lpop
127.0.0.1:6379> lrange list 0 -1
1) "three"
2) "tow"
3) "one"
4) "four"
127.0.0.1:6379> lpop list # 移除列表第一个元素
"three"
127.0.0.1:6379> rpop list # 移除列表最后一个元素
"four"
127.0.0.1:6379> lrange list 0 -1
1) "tow"
2) "one"
###########################################
# lindex
127.0.0.1:6379> lrange list 0 -1
1) "tow"
2) "one"
127.0.0.1:6379> lindex list 0 # 通过下标获取 list 中的值.
"tow"
127.0.0.1:6379> lindex list 1
"one"
###########################################
# llen
127.0.0.1:6379> llen list # 返回列表长度
(integer) 2
###########################################
# 移除指定的值 # lrem
127.0.0.1:6379> lrange list 0 -1
1) "tow"
2) "one"
127.0.0.1:6379> lrem list 1 one # 移除 list 集合中指定个数的 value,精确匹配
(integer) 1
127.0.0.1:6379> lrange list 0 -1
1) "tow"
127.0.0.1:6379> lpush list tow
(integer) 2
127.0.0.1:6379> lpush list three
(integer) 3
127.0.0.1:6379> lrange list 0 -1
1) "three"
2) "tow"
3) "tow"
127.0.0.1:6379> lrem list 2 three
(integer) 1
127.0.0.1:6379> lrange list 0 -1
1) "tow"
2) "tow"
###########################################
# trim list 截取
127.0.0.1:6379> rpush mylist "hello"
(integer) 1
127.0.0.1:6379> RPUSH mylist "hello1"
(integer) 2
127.0.0.1:6379> rpush mylist "hello2"
(integer) 3
127.0.0.1:6379> rpush mylist "hello4"
(integer) 4
127.0.0.1:6379> lrange mylist 0 -1
1) "hello"
2) "hello1"
3) "hello2"
4) "hello4"
127.0.0.1:6379> ltrim mylist 1 2 # 通过下标截取指定位置元素
OK
127.0.0.1:6379> lrange mylist 0 -1
1) "hello1"
2) "hello2"
###########################################
# rpoplpush # 移除列表尾部元素并添加到新列表中
127.0.0.1:6379> rpush mylist "hel1o"
(integer) 1
127.0.0.1:6379> rpush mylist "hello1"
(integer) 2
127.0.0.1:6379> rpush mylist "hello2"
(integer) 3
127.0.0.1:6379> rpoplpush mylist otherlist # 移除列表尾部元素并添加到新列表中
"hello2"
127.0.0.1:6379> lrange mylist 0 -1 # 原来列表
1) "hel1o"
2) "hello1"
127.0.0.1:6379> lrange otherlist 0 -1 # 目标列表
1) "hello2"
###########################################
# 列表中指定下标的值替换为另外的值,更新操作
127.0.0.1:6379> exists list # 判断列表是否存在
(integer) 0
127.0.0.1:6379> lset list 0 item # 不存在就会报错
(error) ERR no such key
127.0.0.1:6379> lpush list value1
(integer) 1
127.0.0.1:6379> lrange list 0 0
1) "value1"
127.0.0.1:6379> lset list 0 item # 如果存在更新下标的值
OK
127.0.0.1:6379> lrange list 0 0
1) "item"
127.0.0.1:6379> lset list 1 item2 # 不存在就会报错
(error) ERR index out of range
###########################################
# linsert # 将某个具体的具体的 value 值插入列表中
127.0.0.1:6379> rpush list hello
(integer) 1
127.0.0.1:6379> rpush list word
(integer) 2
127.0.0.1:6379> linsert list before word other # 插入到指定值之前
(integer) 3
127.0.0.1:6379> lrange list 0 -1
1) "hello"
2) "other"
3) "word"
127.0.0.1:6379> linsert list after word new
(integer) 4
127.0.0.1:6379> lrange list 0 -1
1) "hello"
2) "other"
3) "word"
4) "new"
  • list is a linked list, before, after, left, right can be inserted into values
  • If the key does not exist, create a new linked list
  • If the key exists, add content
  • If all values ​​are removed, empty linked list does not exist
  • Inserting or changing values ​​on both sides is the most efficient.

Application scenarios:

Message queue Stack = LPUSH + LPOP
stack Queue = LPUSH + RPOP
Blocking MQ = LPUSH + BRPOP
message flow

1.3 hash (hash)

Map collection, key-map collection, the essence is not much different from the string type, it is a simple key-value
commonly used command:

###########################################
127.0.0.1:6379> hset hash 1 2	# set 一个具体的 key - value
(integer) 1
127.0.0.1:6379> hset hash key1 value1
(integer) 1
127.0.0.1:6379> hget hash key1	# 获取 指定 key 的值
"value1"
127.0.0.1:6379> hmset hash key value key2 value2	# set 多个 key - value
OK
127.0.0.1:6379> hmget  hash key 1 key2	# get 多个字段值
1) "value"
2) "2"
3) "value2"
127.0.0.1:6379> hgetall hash	# 获取所有 key - value 数据
1) "1"
2) "2"
3) "key1"
4) "value1"
5) "key"
6) "value"
7) "key2"
8) "value2"
###########################################
127.0.0.1:6379> hdel hash 1	# 删除指定 key 的 value
(integer) 1
127.0.0.1:6379> hgetall hash
1) "key1"
2) "value1"
3) "key"
4) "value"
5) "key2"
6) "value2"
###########################################
127.0.0.1:6379> hlen hash	# 获取 hash 表的字段数量
(integer) 3
127.0.0.1:6379> hmset hash hello word
OK
127.0.0.1:6379> hgetall hash
1) "key1"
2) "value1"
3) "key"
4) "value"
5) "key2"
6) "value2"
7) "hello"
8) "word"
###########################################
127.0.0.1:6379> HEXISTS hash key1	# 判断 hash 中的指定字段是否存在
(integer) 1
127.0.0.1:6379> hexists hash key3
(integer) 0
###########################################
127.0.0.1:6379> hkeys hash	# 只获得所有的 key
1) "key1"
2) "key"
3) "key2"
4) "hello"
127.0.0.1:6379> hvals hash	# 只获得所有的 value
1) "value1"
2) "value"
3) "value2"
4) "word"
###########################################
127.0.0.1:6379> hset hash star 5
(integer) 1
127.0.0.1:6379> hget hash star
"5"
127.0.0.1:6379> HINCRBY hash star 1	# 指定增量 1
(integer) 6
127.0.0.1:6379> HINCRBY hash star -1
(integer) 5
127.0.0.1:6379> hsetnx hash value3 hello	# 如果不存在可以设置
(integer) 1
127.0.0.1:6379> hsetnx hash value3 word	# 存在则不能设置
(integer) 0

Application scenarios:

Change data, user information is stored, the information often changes, for object storage
cart

1.4 set (collection)

The value in set cannot be repeated
Commonly used commands:

###########################################
127.0.0.1:6379> sadd set hello # set 集合中添加元素
(integer) 1
127.0.0.1:6379> sadd set hello1
(integer) 1
127.0.0.1:6379> sadd set hello2
(integer) 1
127.0.0.1:6379> SMEMBERS set	# 查看指定 set 的所有值
1) "hello2"
2) "hello1"
3) "hello"
127.0.0.1:6379> SISMEMBER set hello # 查看某个值是否在 set 集合中,存在为 1,不存在为 0
(integer) 1
127.0.0.1:6379> SISMEMBER set word
(integer) 0
###########################################
127.0.0.1:6379> scard set	# 获取 set 集合中的元素个数
(integer) 3
127.0.0.1:6379> sadd set hello
(integer) 0
127.0.0.1:6379> sadd set hello3
(integer) 1
127.0.0.1:6379> scard set
(integer) 4
###########################################
127.0.0.1:6379> srem set hello	# 移除某个元素
(integer) 1
127.0.0.1:6379> scard set
(integer) 3
127.0.0.1:6379> SMEMBERS set
1) "hello2"
2) "hello1"
3) "hello3"
###########################################
127.0.0.1:6379> SRANDMEMBER set	# 随机抽取一个元素
"hello1"
127.0.0.1:6379> SRANDMEMBER set
"hello3"
127.0.0.1:6379> SRANDMEMBER set
"hello2"
127.0.0.1:6379> SRANDMEMBER set
"hello3"
127.0.0.1:6379> srandmember set 2	# 随机抽取指定个数元素
1) "hello1"
2) "hello2"
###########################################
# 删除指定的 key,删除随机的 key
127.0.0.1:6379> spop set	# 随机删除一些 set 集合中的元素
"hello3"
127.0.0.1:6379> spop set
"hello2"
127.0.0.1:6379> SMEMBERS set
1) "hello1"
127.0.0.1:6379> SMEMBERS set
1) "hello1"
###########################################
# 一个指定的值,移动到另外一个集合中。
127.0.0.1:6379> sadd set hello
(integer) 1
127.0.0.1:6379> sadd set hello1
(integer) 1
127.0.0.1:6379> sadd set hello2
(integer) 1
127.0.0.1:6379> sadd set hello3
(integer) 1
127.0.0.1:6379> sadd set2 hello
(integer) 1
127.0.0.1:6379> smove set set2 hello1	# # 一个指定的值,移动到另外一个集合中。
(integer) 1
127.0.0.1:6379> SMEMBERS set2
1) "hello1"
2) "hello"
###########################################
# 交集,差集,并集
127.0.0.1:6379> sadd key1 a
(integer) 1
127.0.0.1:6379> sadd key1 b
(integer) 1
127.0.0.1:6379> sadd key1 c
(integer) 1
127.0.0.1:6379> sadd key2 d
(integer) 1
127.0.0.1:6379> sadd key2 c
(integer) 1
127.0.0.1:6379> sadd key2 e
(integer) 1
127.0.0.1:6379> SDIFF key1 key2	# 查看差集
1) "a"
2) "b"
127.0.0.1:6379> SINTER key1 key2	# 交集 共同好友
1) "c"
127.0.0.1:6379> SUNION key1 key2	# 并集
1) "c"
2) "a"
3) "b"
4) "e"
5) "d"

Application scenarios:

Mutual friends, follow together, recommend friends, etc.
Commodity screening,
lottery,
friends de-duplication

1.5 zset (ordered set)

Sorting is added on the basis of set.
Commonly used commands:

###########################################
127.0.0.1:6379> zadd set 1 one	# 添加一个值
(integer) 1
127.0.0.1:6379> zadd set 2 two
(integer) 1
127.0.0.1:6379> zadd set 3 three 4 four	# 添加多个值
(integer) 2
127.0.0.1:6379> zrange set 0 -1
1) "one"
2) "two"
3) "three"
4) "four"
###########################################
# 排序实现
127.0.0.1:6379> zadd sala 2500 xiaoming	# 添加三个用户
(integer) 1
127.0.0.1:6379> zadd sala 3000 zhangsan
(integer) 1
127.0.0.1:6379> zadd sala 1500 xiaohong
(integer) 1
127.0.0.1:6379> ZRANGEBYSCORE sala -inf +inf	# 最小值到最大值排序
1) "xiaohong"
2) "xiaoming"
3) "zhangsan"
127.0.0.1:6379> ZREVRANGE sala 0 -1	# 最大值到最小值排序
1) "zhangsan"
2) "xiaoming"
127.0.0.1:6379> ZRANGEBYSCORE sala -inf +inf withscores	# 最小值到最大值排序并附带成绩
1) "xiaohong"
2) "1500"
3) "xiaoming"
4) "2500"
5) "zhangsan"
6) "3000"
127.0.0.1:6379> ZRANGEBYSCORE sala -inf 2500 withscores	# 工资小于 2500 升排列
1) "xiaohong"
2) "1500"
3) "xiaoming"
4) "2500"
###########################################
127.0.0.1:6379> zrange sala 0 -1
1) "xiaohong"
2) "xiaoming"
3) "zhangsan"
127.0.0.1:6379> zrem sala xiaohong	# 移除元素
(integer) 1
127.0.0.1:6379> zrange sala 0 -1
1) "xiaoming"
2) "zhangsan"
###########################################
127.0.0.1:6379> zcard sala	# 获取有序集合中的个数
(integer) 2
###########################################
127.0.0.1:6379> ZREVRANGE sala 0 -1
1) "zhangsan"
2) "xiaoming"
127.0.0.1:6379> zadd sala 1 hello 2 word
(integer) 2
127.0.0.1:6379> zcount  sala 1 2	# 获取指定区间的元素数量
(integer) 2
127.0.0.1:6379> zrange sala 0 -1
1) "hello"
2) "word"
3) "xiaoming"
4) "zhangsan"

Application scenarios:

Rankings
to judge by weight

1.6 geospatial (geographical location)

Nearby people, location, latitude and longitude query, distance calculation, etc.

1.7 hyperloglog (base statistics)

A(1,3,5,7,8,7) B(1,3,5,7,8)
base is the number of elements in the set after removing duplicate elements = 5
Advantages: fixed memory usage, 12 KB

127.0.0.1:6379> pfadd key1 a b c d e f	# 创建第一组元素
(integer) 1
127.0.0.1:6379> pfadd key2 g h l m n a	# 创建第二组元素
(integer) 1
127.0.0.1:6379> pfcount key1	# 查看元素数量
(integer) 6
127.0.0.1:6379> pfcount key2
(integer) 6
127.0.0.1:6379> PFMERGE key3 key1 key2	# 合并两组并集到 key3
OK
127.0.0.1:6379> pfcount key3
(integer) 11

scenes to be used

The UV of a webpage, a person visits a website many times, but counted as a person, there is a certain error rate, and can be used with fault tolerance

1.8 bitmaps (bitmap scene)

Bit storage, data structure, operation binary for recording

127.0.0.1:6379> setbit sign 0 0	# 赋值
(integer) 0
127.0.0.1:6379> setbit sign 1 0
(integer) 0
127.0.0.1:6379> setbit sign 2 0
(integer) 0
127.0.0.1:6379> setbit sign 3 0
(integer) 0
127.0.0.1:6379> setbit sign 4 1
(integer) 0
127.0.0.1:6379> getbit sign 3	# 获取 指定 key 的值
(integer) 0
127.0.0.1:6379> getbit sign 4
(integer) 1
127.0.0.1:6379> bitcount sign	# 计算累加值
(integer) 1

scenes to be used

Statistics User Information
punch