240527_Redis

Haoliang Tang Lv3

安装

https://wiki.archlinux.org/title/Redis

1
sudo pacman -S redis

启动redis-server

1
systemctl start redis

(其实本质是/usr/bin/redis-server /etc/redis/redis.conf) (from redis.service里的ExecStart)

(在某个目录下redis-server也可以,然后要持久化的话,会在这个目录下生成一个dump.rdb的文件)

可以用systemctl status查看,也可以ps -ef | grep redis看到redis已经启动了


可以编辑/etc/redis/redis.conf里的requirepass设置口令

命令行操作

https://redis.io/docs/latest/commands/

使用redis-cli

1
redis-cli ping

测试连接,得到一个PONG的返回

直接终端输入 redis-cli,不带command,就进入交互模式

1
2
3
4
5
6
7
8
9
10
11
redis-cli
127.0.0.1:6379> ping
PONG
127.0.0.1:6379> set name yukawa
OK
127.0.0.1:6379> set age 25
OK
127.0.0.1:6379> get name
"yukawa"
127.0.0.1:6379> get age
"25"

若redis.conf设置了requirepass口令,则要redis-cli -a 口令登录,不然(error) NOAUTH Authentication required.

也可以先不-a指定口令,直接redis-cli连上后,再auth 口令

1
2
127.0.0.1:6379> auth chedishibai
OK

GUI客户端

DbGate支持Redis

试试Redis Insight

1
paru -S redisinsight

操作5种基本数据结构类型

Redis是key-value的数据库,key都是String类型,value有8种,其中有5中常见基本类型:String,Hash,List,Set,SortedSet

没必要死记硬背,不知道就去官网文档按group查看,或者命令行help @xxx

不分数据类型,通用的命令

https://redis.io/docs/latest/commands/?group=generic

官网文档filter by group选generic,或者127.0.0.1:6379> help @generic,但官网文档有使用例子,更详细。

  • KEYS, DEL, EXISTS (keys *因为效率问题不建议生产环境使用)
1
2
3
4
5
6
7
8
127.0.0.1:6379> del age
(integer) 1
127.0.0.1:6379> keys *
1) "name"
127.0.0.1:6379> exists age
(integer) 0
127.0.0.1:6379> exists name
(integer) 1

可见age被删掉了

  • EXPIRE: 给key设置有效期,有效期到了会自动删除该key,节约内存
  • TTL: 查看一个key的剩余有效期
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
127.0.0.1:6379> help expire 

EXPIRE key seconds [NX|XX|GT|LT]
summary: Sets the expiration time of a key in seconds.
since: 1.0.0
group: generic

127.0.0.1:6379> expire name 20
(integer) 1
127.0.0.1:6379> ttl name
(integer) 16
127.0.0.1:6379> ttl name
(integer) 8
127.0.0.1:6379> ttl name
(integer) 6
127.0.0.1:6379> ttl name
(integer) 5
127.0.0.1:6379> ttl name
(integer) -2

最后ttl有效期输出-2,说明有效期到期被删了,数据库里没有这个key了

如果set一个key-value时不指定expire,那ttl输出-1,说明TTL: No limit永久有效

String

https://redis.io/docs/latest/commands/?group=string

  • SET: 增或改,键值对不存在就添加,存在则修改(overwritten, regardless of its type)
  • GET: Get the value of key. If the key does not exist the special value nil is returned. An error is returned if the value stored at key is not a string, because GET only handles ==string values==.
  • MSET, MGET
1
2
3
4
5
6
7
8
9
10
11
12
13
14
127.0.0.1:6379> set name Tang
OK
127.0.0.1:6379> get name
"Tang"
127.0.0.1:6379> set age 18
OK
127.0.0.1:6379> mset name Yukawa age 25 k1 v1 k2 v2 k3 v3
OK
127.0.0.1:6379> mget name age k1 k2 k3
1) "Yukawa"
2) "25"
3) "v1"
4) "v2"
5) "v3"
  • INCR: Increments the number stored at key by one.
  • INCRBY, INCRBYFLOAT
  • SETNX: Set key to hold string value if key does not exist. In that case, it is equal to SET. When key already holds a value, no operation is performed. SETNX is short for “SET if Not eXists”. 真正的新增
  • SETEX: set同时设置expire https://redis.io/docs/latest/commands/setex/

通过namespace给Key分层

Redis作为key-value型的数据库,那自然要求key是唯一的。但我们存一些数据,一般用id作为key。但如果涉及到多个类型,两个不同class的object的id都是1,如何区分不同class的id。

:隔开实现key的层级结构

eg. [项目名]:[业务名]:[类型]:[id]

比如项目名称叫wuxia,有user和wugong两种数据类型,可以这样定义key:

  • wuxia:user:1
  • wuxia:wugong:1

value往往是一个对象。虽然对象本身不是String,但完全可以把对象序列化成JSON字符串存储

KEY VALUE
wuxia:user:1 {“id”: 1, “name”: “张三丰”, “age”: 80}
wuxia:wugong:1 {“id”: 1, “name”: “降龙十八掌”, “description”: “降龍十八掌為丐幫至剛至陽之鎮幫掌法,主要以威猛力道稱雄江湖,大成後足以問鼎江湖。”}

注意redis-cli操作时value要加上''在最外面

1
2
3
4
127.0.0.1:6379> set wuxia:user:1 {"id": 1, "name": "张三丰", "age": 80}
Invalid argument(s)
127.0.0.1:6379> set wuxia:user:1 '{"id": 1, "name": "张三丰", "age": 80}'
OK

但RedisInsight图形界面里add key时不需要再value那加’’了

RedisInsight等GUI里可以以tree状分层展示键值对了

Hash

value是个无序字典,相当于hashmap的值又套娃了个hashmap

刚才那样把value存为对象序列化后的json字符串的弊端在于很难对object的某个字段做修改

Hash类型可以可以把对象的每个字段独立存储,可以对单个字段做CRUD

https://redis.io/docs/latest/commands/?group=hash

KEY VALUE
wuxia:user:2 {“id”: 2, “name”: “张无忌”, “age”: 20}
wuxia:wugong:2 {“id”: 2, “name”: “九阳神功”, “description”: “练成「九阳神功」内力自生速度奇快,似无穷尽;普通拳脚也能使出绝大威力,防御反弹外力攻击,习者速度将受到极大加成,更是疗伤圣典,百病不生,诸毒不侵。”}
  • HSET, HGET, HGETALL
1
2
3
4
5
6
7
8
9
10
11
127.0.0.1:6379> hset wuxia:user:2 name 张无忌
(integer) 1
127.0.0.1:6379> hset wuxia:user:2 age 20
(integer) 1
127.0.0.1:6379> hget wuxia:user:2 age
"20"
127.0.0.1:6379> hgetall wuxia:user:2
1) "name"
2) "\xe5\xbc\xa0\xe6\x97\xa0\xe5\xbf\x8c"
3) "age"
4) "20"
  • HMSET, HMGET(绝对用HGETALL方便)
1
2
3
4
5
127.0.0.1:6379> hmset wuxia:wugong:2 name 九阳神功 description 练成「九阳神功」内力自生速度奇快,似无穷尽;普通拳脚也能使出绝大威力,防御反弹外力攻击,习者速度将受到极大加成,更是疗伤圣典,百病不生,诸毒不侵。
OK
127.0.0.1:6379> hmget wuxia:wugong:2 name description
1) "\xe4\xb9\x9d\xe9\x98\xb3\xe7\xa5\x9e\xe5\x8a\x9f"
2) "\xe7\xbb\x83\xe6\x88\x90\xe3\x80\x8c\xe4\xb9\x9d\xe9\x98\xb3\xe7\xa5\x9e\xe5\x8a\x9f\xe3\x80\x8d\xe5\x86\x85\xe5\x8a\x9b\xe8\x87\xaa\xe7\x94\x9f\xe9\x80\x9f\xe5\xba\xa6\xe5\xa5\x87\xe5\xbf\xab\xef\xbc\x8c\xe4\xbc\xbc\xe6\x97\xa0\xe7\xa9\xb7\xe5\xb0\xbd\xef\xbc\x9b\xe6\x99\xae\xe9\x80\x9a\xe6\x8b\xb3\xe8\x84\x9a\xe4\xb9\x9f\xe8\x83\xbd\xe4\xbd\xbf\xe5\x87\xba\xe7\xbb\x9d\xe5\xa4\xa7\xe5\xa8\x81\xe5\x8a\x9b\xef\xbc\x8c\xe9\x98\xb2\xe5\xbe\xa1\xe5\x8f\x8d\xe5\xbc\xb9\xe5\xa4\x96\xe5\x8a\x9b\xe6\x94\xbb\xe5\x87\xbb\xef\xbc\x8c\xe4\xb9\xa0\xe8\x80\x85\xe9\x80\x9f\xe5\xba\xa6\xe5\xb0\x86\xe5\x8f\x97\xe5\x88\xb0\xe6\x9e\x81\xe5\xa4\xa7\xe5\x8a\xa0\xe6\x88\x90\xef\xbc\x8c\xe6\x9b\xb4\xe6\x98\xaf\xe7\x96\x97\xe4\xbc\xa4\xe5\x9c\xa3\xe5\x85\xb8\xef\xbc\x8c\xe7\x99\xbe\xe7\x97\x85\xe4\xb8\x8d\xe7\x94\x9f\xef\xbc\x8c\xe8\xaf\xb8\xe6\xaf\x92\xe4\xb8\x8d\xe4\xbe\xb5\xe3\x80\x82"
  • HKEYS, HVALS
1
2
3
4
5
6
127.0.0.1:6379> hkeys wuxia:user:2
1) "name"
2) "age"
127.0.0.1:6379> hvals wuxia:user:2
1) "\xe5\xbc\xa0\xe6\x97\xa0\xe5\xbf\x8c"
2) "20"
  • HSETNX: 这次判断的是field存不存在

List

底层可以看作是双向链表的结构。既可以正向检索,也可以反向检索。

特征:有序,元素可以重复,插入删除快,查询速度慢

使用场景为需要順番つけ的列表

https://redis.io/docs/latest/commands/?group=list

  • RPUSH, RPOP
  • LPUSH, LPOP
  • LLEN
  • LRANGE: 类似Python切片
1
2
3
4
5
6
7
8
9
10
11
12
13
127.0.0.1:6379> rpush arr "one" 2 "three"
(integer) 3
127.0.0.1:6379> llen arr
(integer) 3
127.0.0.1:6379> lrange arr 0 2
1) "one"
2) "2"
3) "three"
127.0.0.1:6379> lpop arr 2
1) "one"
2) "2"
127.0.0.1:6379> lrange arr -10 10
1) "three""

Set

HashSet

支持交集,并集,差集,实现业务里的共同好友列表

https://redis.io/docs/latest/commands/?group=set

  • SADD: 添加一个或多个元素 O(1) for each element added, so O(N) to add N elements when the command is called with multiple arguments.
  • SREM: Removes one or more members from a set. Deletes the set if the last member was removed.
  • SPOP: 随机移除一个幸运儿
  • SCARD: 返回set中元素个数
  • SISMEMBER: 判断一个元素是否在set里
  • SMEMBERS: 返回set里的所有元素
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
127.0.0.1:6379> sadd myset "Hello" a b c 1 2 3
(integer) 7
127.0.0.1:6379> smembers myset
1) "Hello"
2) "a"
3) "b"
4) "c"
5) "1"
6) "2"
7) "3"
127.0.0.1:6379> srem myset a
(integer) 1
127.0.0.1:6379> sismember myset a
(integer) 0
127.0.0.1:6379> scard myset
(integer) 6
  • SINTER: Returns the members of the set resulting from the intersection of all the given sets.
  • SDIFF: 差集
  • SUNION: Returns the members of the set resulting from the union of all the given sets.
  • SINTERSTORE, SUNIONSTORE, SDIFFSTORE

SortedSet

排序根据score

用来实现排行榜功能

https://redis.io/docs/latest/commands/?group=sorted-set

  • ZADD, ZREM
  • ZSCORE: 获取指定元素的score值 (用来判断元素是否存在,不存在返回nil,zset没有ISMEMBER方法)
  • ZRANK: 获取指定元素的排名
  • ZCARD: 返回zset中元素个数
  • ZINCRBY
  • ZCOUNT: 统计score在指定范围内的元素个数
  • ZRANGE: 按照名次范围取元素
  • ZRANGEBYSCORE: 按照score范围取元素
  • ZINTER, ZUNION, ZDIFF: 交并差

注意:所有排名默认是升序,若要降序在命令的Z后面加上REV

1
2
3
4
5
6
7
8
9
10
127.0.0.1:6379> ZADD myzset 1 "one"
(integer) 1
127.0.0.1:6379> ZADD myzset 2 "two" 3 "three" 4 four 5 five
(integer) 4
127.0.0.1:6379> ZREVRANK myzset one
(integer) 4 下标从0开始
127.0.0.1:6379> zrevrange myzset 0 2 找前三名
1) "five"
2) "four"
3) "three"

Python客户端

https://redis.io/docs/latest/develop/connect/clients/python/

https://pypi.org/project/redis/

https://redis.readthedocs.io/en/stable/examples/connection_examples.html

安装==redis-py==

1
2
pip install redis
sudo pacman -S python-redis

连接redis与使用

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
import redis

r = redis.Redis(host='localhost', port=6379,
password='chedishibai', decode_responses=True, db=0) # db=0代表redis数据库0-15中的哪一个
print(r.ping())

r.set('foo', 'bar')
print(r.get('foo'))
print(type(r.get('foo')))

r.hset('user-session:123', mapping={
'name': 'John',
"surname": 'Smith',
"company": 'Redis',
"age": 29
})
print(r.hgetall('user-session:123'))
print(type(r.hgetall('user-session:123')))

key_list = r.keys('*')
print(key_list)

r.rpush('py_l1', "one", 2, "three")
print(r.lrange('py_l1', 0, -1))

https://www.bilibili.com/video/BV1T54y1U7kb

Java客户端

https://redis.io/docs/latest/develop/connect/clients/java/jedis/

  • Title: 240527_Redis
  • Author: Haoliang Tang
  • Created at : 2024-05-27 00:00:00
  • Updated at : 2025-04-29 23:57:06
  • Link: https://hl-tang.github.io/2024/05/27/240527_Redis/
  • License: This work is licensed under CC BY-NC-SA 4.0.
Comments