Redis手记之数据类型

1.前言

一直以为自己会redis,但是从没有系统的学过,对于redis的理解还是只停留在set key、get key这些基础的命令上。现在查漏补缺,重新学习一遍,增加一下对redis的了解。

2.Redis的key

redis的key除了set 和 get之外。还有exists, expire, keys, expireat, ttl等很多,常用的如下:

命令 说明 demo
exists 检查当前库里面是否存在某个key

127.0.0.1:6379> exists name
(integer) 1

expire

设置key的过期时间,单位秒

pexpire单位是毫秒 pexpireat同毫秒

127.0.0.1:6379> expire name 2000
(integer) 1
expireat 设置key的过期时间,单位时间戳,这个在某些特殊场景还是挺有用的 127.0.0.1:6379> EXPIREAT name 1576234458
(integer) 1
127.0.0.1:6379> ttl name
(integer) 86369
persist 取消key的过期时间,key将永久保存 127.0.0.1:6379> persist name
(integer) 1
127.0.0.1:6379> ttl name
(integer) -1
keys 返回符合条件的key(生产环境慎用 keys *,或者禁用) 127.0.0.1:6379> keys na*
1) "name"
ttl 查看key的剩余过期时间 127.0.0.1:6379> ttl name
(integer) 1773
rename 重命名一个key,如果newname已存在,则会覆盖 127.0.0.1:6379> get name
"smallking"
127.0.0.1:6379> set name2 "tom"
OK
127.0.0.1:6379> rename name2 name
OK
127.0.0.1:6379> get name
"tom"
incr 自增+1,如果 key 不存在,那么 key 的值会先被初始化为 0 127.0.0.1:6379> set i 1
OK
127.0.0.1:6379> incr i
(integer) 2
127.0.0.1:6379> get i
"2"

3.Redis hash

hash是redis的数据类型之一,比较适合用来存储对象。语法如下:

命令 说明 demo
hmset

添加一个或者多个键值对到key对应的hash表中。以前认为hmset是hashMapSet的缩写,后来看到还有一个hset,所以hmset应该hash multi set的缩写。一次可以设置多个,而hset只能设置一个

127.0.0.1:6379> hmset user01 id 001 name smallking age 18
OK
hmget 得到指定key对应hash表的多个key-value 127.0.0.1:6379> HMGET user01 id name
1) "001"
2) "smallking"
hset和hget 同hmset和hmget不同的是,一次只能操作hash的一个键值对 127.0.0.1:6379> hset user01  email [email protected]
(integer) 1
127.0.0.1:6379> hget user01 email
"[email protected]"
hgetall 得到一个hash表的所有字段 127.0.0.1:6379> hgetall user01
1) "id"
2) "001"
3) "name"
4) "smallking"
5) "age"
6) "18"
7) "email"
8) "[email protected]"
hkeys 得到指定hash表的所有key 127.0.0.1:6379> hkeys user01
1) "id"
2) "name"
3) "age"
4) "email"
hvals 得到指定hash表的所有value 127.0.0.1:6379> HVALS user01
1) "001"
2) "smallking"
3) "18"
4) "[email protected]"

除了表中的这些,redis的hash还有其他一些命令,很多命令都是见名知意。hash可以用来存储对象,但是如果将对象转为json字符串,以key-jsonstr存在redis里更方便,一般不经常修改的对象,可以存jsonstr,但是如果对象要经常修改的话,还是存hash比较方便。

4.Redis list 

一直都将redis的list当成一个java的ArrayList<String> 来看,其实它是个linkedList<String>。当我们想到一个list的时候,list.add()增加元素,list.get(index) 获得元素,list.size()获取列表长度,这些功能redis的list都具备:

命令 说明 demo
lpush 在list的头部添加元素 127.0.0.1:6379> lpush idlist 1 2 3 4 5
(integer) 5
llen llen即 list length 获取list的长度 127.0.0.1:6379> llen idlist
(integer) 5
lrange  获取list的一段值  127.0.0.1:6379> lrange idlist 0 100
1) "5"
2) "4"
3) "3"
4) "2"
5) "1"
lindex 获取指定下标的值 127.0.0.1:6379> lindex idlist 3
"2"
lpop 移除并返回第一个元素 127.0.0.1:6379> lpop idlist
"5"
127.0.0.1:6379> lrange idlist 0 100
1) "4"
2) "3"
3) "2"
4) "1"
lpush 在头部插入一个元素 127.0.0.1:6379> lpush idlist 10
(integer) 5
127.0.0.1:6379> lrange idlist 0 100
1) "10"
2) "4"
3) "3"
4) "2"
5) "1"

redis的list除了以上操作,还有通过BLPOP/BRPOP来实现简单的消息队列,这两个命令都是阻塞的。当程序中有简单消息队列的需要,但是对于消息的可靠性性要求不高的时候,可以使用BLPOP/BRPOP来简单快速的实现消息队列需求。简单实现如下:

生产者

import com.smallking.redis.speed.JedisManager;

import redis.clients.jedis.Jedis;

public class Producer {
	
	public static void main(String[] args) {
		Jedis jedis = JedisManager.instance().getJedis();
		Long lpush = jedis.lpush("message", "消息内容:" + Math.random());
		System.out.println("list大小:" + lpush);
	}
	
}

消费者

import java.util.List;

import com.smallking.redis.speed.JedisManager;

import redis.clients.jedis.Jedis;

public class Comsumer {

	public static void main(String[] args) {
		Jedis jedis = JedisManager.instance().getJedis();
		while(true) {
			List<String> list = jedis.blpop(0, "message");
			for(String str : list) {
				System.out.println("处理消息" + str);
			}
		}
	}

}

redis的list通过lrange命令还可以实现定时计算的,并且计算之后就不会更改的排行榜,如去年的班级成绩排名,上个月的出勤率等,但是如果是经常变化的list就不推荐用list了,后面会说到可以用sorted set。还有一些时间线很明显的数据也可以通过list的lpush来实现。

5.Redis set

redis的set存储的元素是无序且唯一的。除了对set的基础增删改查之外,我们还应该灵活运用set的交并插计算来应对一些场景。

命令 说明 demo
sadd  为一个set集合添加一个或者多个元素 127.0.0.1:6379> sadd user 1 2 3
(integer) 3
smembers 获得一个set集合的所有元素 127.0.0.1:6379> SMEMBERS user
1) "1"
2) "2"
3) "3"
srem 移除一个或者多个元素 127.0.0.1:6379> SREM user 1 2
(integer) 2
sdiff 求所给集合的差集 127.0.0.1:6379> sadd set1 1 2 3 4
(integer) 4
127.0.0.1:6379> sadd set2 2 5 6 7
(integer) 4
127.0.0.1:6379> sdiff set1 set2
1) "1"
2) "3"
3) "4"
sunion 求所给集合的并集 127.0.0.1:6379> sunion set1 set2
1) "1"
2) "2"
3) "3"
4) "4"
5) "5"
6) "6"
7) "7"
sinter 求交集 127.0.0.1:6379> sinter set1 set2
1) "2"

redis的set集合可以给我们解决很多问题,例如:

  • set的唯一性可以用来做uv统计,一天一个用户多次访问本网站算做一次uv,则可以用日期作为key,当用户访问网站的时候直接sadd当前客户的ID就好了。
  • set的sinter可以用来做好友推荐,需求:现在有2个用户,如果这两个用户的共同好友超过3人,则推荐他们加好友。我们可以用用户的id作为key,将用户的好友存储在set里面,sinter userid1 userid2就得到了2个人的共同好友,判断共同好友的数量,决定是否推荐。
  • 当业务需要求交集并集差集的时候,可以朝着redis set上面想一想,也许一下子就变的简单了呢。

6.Redis sorted set

sorted set是有序的集合,它给每个set元素都加了一个score分数,通过这个分数来进行排序。

命令 说明 demo
zadd 添加元素 如果元素已则会更新元素的score 127.0.0.1:6379> zadd ganmerank 200.5 xiaowang 300 xiaozhang 400 xiaoli
(integer) 3
zrange 按照下标查询元素 127.0.0.1:6379> zrange ganmerank 0 100 withscores
1) "xiaowang"
2) "200.5"
3) "xiaozhang"
4) "300"
5) "xiaoli"
6) "400"
zrangebyscore 按照分数来查询元素 127.0.0.1:6379> zrangebyscore gamerank 1 1000 withscores
1) "xiaowang"
2) "200.5"
3) "xiaozhang"
4) "300"
5) "xiaoli"
6) "400"
zrem 删除元素 127.0.0.1:6379> zrange gamerank 0 200
1) "xiaowang"
2) "xiaoli"
127.0.0.1:6379> zrem gamerank xiaoli
(integer) 1
127.0.0.1:6379> zrange gamerank 0 -1
1) "xiaowang"
ZINCRBY 给某个元素加分 127.0.0.1:6379> zrange gamerank 0 -1 withscores
1) "xiaowang"
2) "200.5"
127.0.0.1:6379> ZINCRBY gamerank 1 xiaowang
"201.5"

sorted set 很适用一些实时变化的排行场景,比如某论坛的文章排序规则是按照阅读量,那么可以用文章的id作为sorted set的元素,阅读量作为score。当一个文章阅读量发生变化的时候ZINCRBY +1 就好了。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章