一、 redis 特点
- 所有数据存储在内存中,高速读写
- 提供丰富多样的数据类型:string、 hash、 set、 sorted set、bitmap、hyperloglog
- 提供了 AOF 和 RDB 两种数据的持久化保存方式,保证了 Redis 重启后数据不丢失
- Redis 的所有操作都是原子性的,还支持对几个操作合并后的原子性操作,支持事务
通常我们都把数据存到关系型数据库中,但为了提升应用的性能,我们应该把访频率高且不会经常变动的数据缓存到内存中。。Redis 没有像 MySQL 这类关系型数据库那样强大的查询功能,需要考虑如何把关系型数据库中的数据,合理的对应到缓存的 key-value 数据结构中。
二、 设计 Redis Key
分段设计法
使用冒号把 key 中要表达的多种含义分开表示,步骤如下:
- 把表名转化为 key 前缀
- 主键名(或其他常用于搜索的字段)
- 主键值
- 要存储的字段。
eg. 用户表(user)
id | name | |
---|---|---|
1 | zj | 1234@163.com |
2 | ai | 1234@163.com |
这个简单的表可能经常会有这个的需求:>根据用户 id 查询用户邮箱地址,可以选择把邮箱地址这个数据存到 redis 中:
set user:id:1:email 1234@163.com;
set user:id:2:email 1234@163.com;
三、 String数据类型的应用场景
1. 简介
string 类型是 Redis 中最基本的数据类型,最常用的数据类型,甚至被很多玩家当成 redis 唯一的数据类型去使用。string 类型在 redis 中是二进制安全(binary safe)的,这意味着 string 值关心二进制的字符串,不关心具体格式,你可以用它存储 json 格式或 JPEG 图片格式的字符串。
2. 数据模型
string 类型是基本的 Key-Value 结构,Key 是某个数据在 Redis 中的唯一标识,Value 是具体的数据。
Key | Value |
---|---|
‘name’ | ‘redis’ |
‘type’ | ‘string’ |
3. 应用场景
(1) 存储 MySQL 中某个字段的值
把 key 设计为 表名:主键名:主键值:字段名
eg.
set user:id:1:email 10000@qq.com
(2) 存储对象
string 类型支持任何格式的字符串,应用最多的就是存储 json 或其他对象格式化的字符串。(这种场景下推荐使用 hash 数据类型)
set user:id:1 '[{"id":1,"name":"zj","email":"10000@qq.com"},{"id":1,"name":"zj","email":"10000@qq.com"}]'
(3) 生成自增 id
当 redis 的 string 类型的值为整数形式时,redis 可以把它当做是整数一样进行自增(incr)自减(decr)操作。由于 redis 所有的操作都是原子性的,所以不必担心多客户端连接时可能出现的事务
问题。
incr 对值进行加1操作,如果不是整数,返回错误,如果不存在按照从0开始
decr 同incr,但是是减1操作
incrby,decrby ,增加减去指定的数
应用场景:比如视频播放次数,点赞次数。
(4)共享session
数据共享的功能,redis作为单独的应用软件用来存储一些共享数据供多个实例访问。
单点登录的一个具体实现
(5)自动定时过期删除
set key value [ex seconds] [px millseconds] [nx|xx]
ex seconds: 键过期时间
px milliseconds: 为键设置毫秒级过期时间
nx: 键必须不存在才可以设置成功,用于添加
xx: 键必须存在,才可以设置成功,用于更新
(6)批量操作
mset,mget
批量设置和获取命令,在操作多个key的时候可以节省网络传输时间
mset key value [key value...]
mget key [key ...]
四、hash 数据类型的应用场景
1. 简介
hash 类型很像一个关系型数据库的数据表,hash 的 Key 是一个唯一值,Value 部分是一个 hashmap 的结构。
2. 数据模型
假设有一张数据库表如下:
id | name | type |
---|---|---|
1 | redis | hash |
如果要用 redis 的 hash 结构存储,数据模型如下:大key:(小key:value)
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-w5dw7zyF-1617613730352)(assets/image-20190503104537583.png)]
hash数据类型在存储上述类型的数据时具有比 string 类型更灵活、更快的优势,具体的说,使用 string 类型存储,必然需要转换和解析 json 格式的字符串,即便不需要转换,在内存开销方面,还是 hash 占优势。 和字符串很像,基本上redis对字符串操作的命令,Redis的Hash一般也存在,不过在命令前多个一个h。
3. 应用场景
hash 类型十分适合存储对象类数据,相对于在 string 中介绍的把对象转化为 json 字符串存储,hash 的结构可以任意添加或删除‘字段名’,更加高效灵活。 一些关系型数据库中不是特别复杂的表,也无需复杂的关系查询,可以使用Redis的Hash来存储,也可以用Hash做表数据缓存。
hmset user:1 name zj email 123456@163.com
hset key field value
hsetnx key field value //与setnx命令一样,不存在则设置值,用于添加,作用在field上面
hget key field //获取值
hdel key field // 删除值
hlen key //子酸field的个数
hmset key field value [filed value] //批量设置field-value
hexists key field //判断filed是否存在
hkeys key //获取所有的field
hvals key //获取所有的value
hgetall key //获取所有的field-value ,如果元素数较多会存在阻塞redis的可能
hincreby key filed
五、list 数据类型的应用场景
1. 简介
list 是按照插入顺序排序的字符串链表,可以在头部和尾部插入新的元素(双向链表实现,两端添加元素的时间复杂度为 O(1))。插入元素时,如果 key 不存在,redis 会为该 key 创建一个新的链表,如果链表中所有的元素都被移除,该 key 也会从 redis 中移除。
2. 数据模型
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-i1msxtZ5-1617613730365)(assets/image-20190503104611445.png)]
链表用来存储多个有序的字符串,一个链表最多可以存储2^32 - 1个元素,在redis中可以对列表的两端插入push和弹出pop,还可以取指定范围的元素。常见操作时用 lpush 命令在 list 头部插入元素, 用 rpop 命令在 list 尾取出数据。
rpush key value [value...] //从右插入元素
lpush key value [value...] //从左边插入元素
lrange key start end //获取指定范围的元素列表
lindex key index //获取列表指定索引下标的元素
llen key //获取列表的长度
lpop key // 从列表左侧弹出元素
rpop key // 从列表右侧弹出元素
lrem key count value //从列表中找到等于value的元素,并进行删除,根据count的不同有不同的情况
lset key index newValue //修改指定索引下标的元素
blpop key timeout //阻塞式左弹出key
brpop key timeout //阻塞式右弹出key
3. 应用场景
(1) 消息队列
redis 的 list 数据类型对于大部分使用者来说,是实现队列服务的最经济,最简单的方式。我司使用redis做消息队列,lpush 、rpop命令,实现先进先出,如果消费失败客户端把key再放回去,消费成功就remove掉。
(2) “最新内容”
因为 list 结构的数据查询两端附近的数据性能非常好,所以适合一些需要获取最新数据的场景,比如新闻类应用的 “最近新闻”。
4.优化建议
(1) list 是链表结构,所有如果在头部和尾部插入数据,性能会非常高,不受链表长度的影响;但如果在链表中插入数据,性能就会越来越差。
####5.使用口诀:
lpush + lpop 栈
lpush + rpop 队列
lpush + ltrim = 有限集合
lpush + brpop = 消息队列
六、set 数据类型的应用场景
1. 简介
set 数据类型是一个集合(没有排序,不重复),可以对 set 类型的数据进行添加、删除、判断是否存在等操作(时间复杂度是 O(1) )
set 集合不允许数据重复,如果添加的数据在 set 中已经存在,将只保留一份。
set 类型提供了多个 set 之间的聚合运算,如求交、并、差集,这些操作在 redis 内部完成,效率很高。
2. 数据模型
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-lEm0yt2J-1617613730368)(/Users/szz/Library/Application Support/typora-user-images/image-20190503104634497.png)]
sadd key value [value...] //添加元素
srem key value [value...] //删除元素
scard key //计算元素的个数
sismember key value //判断元素是否在集合中
srandmember key [count] //随机从集合中返回指定个数的元素,不写默认为1
spop key //从集合随机取出元素
smembers key //获取集合内的所有元素
sinter key1 key2 //求集合的交集
sunion key1 key2 //求集合的并集
sdiff key1 key2 //求集合的差集
3. 应用场景
set 类型的特点是——不重复且无序的一组数据,并且具有丰富的计算功能,在一些特定的场景中可以高效的解决一般关系型数据库不方便做的工作。
(1)“共同好友列表”
社交类应用中,获取两个人或多个人的共同好友,两个人或多个人共同关注的微博这样类似的功能,用 MySQL 的话操作很复杂,可以把每个人的好友 id 存到集合中,获取共同好友的操作就可以简单到一个取交集的命令就搞定。
// 这里为了方便阅读,把 id 替换成姓名
sadd user:wade james melo paul kobe
sadd user:james wade melo paul kobe
sadd user:paul wade james melo kobe
sadd user:melo wade james paul kobe
// 获取 wade 和 james 的共同好友
sinter user:wade user:james
/* 输出:
* 1) "kobe"
* 2) "paul"
* 3) "melo"
*/
// 获取香蕉四兄弟的共同好友
sinter user:wade user:james user:paul user:melo
/* 输出:
* 1) "kobe"
*/
/*
类似的需求还有很多 , 必须把每个标签下的文章 id 存到集合中,可以很容易的求出几个不同标签下的共同文章;
把每个人的爱好存到集合中,可以很容易的求出几个人的共同爱好。
*/
#####(2)唯一ip
跟踪一些具有唯一性的一些数据,比如访问某一博客的唯一ip地址的信息,我们仅需要在每次访问的时候,将ip存入redis中。利用服务器端聚合操作方便高效的特性,维护数据对象之间的关联关系。
七、sorted set 数据类型的应用场景
1.简介
在 set 的基础上给集合中每个元素关联了一个分数,往有序集合中插入数据时会自动根据这个分数排序。它保留了元素不能重复的特性,并且元素是有序的。
2.基本操作
zadd key score member //score是可以重复的,添加key的时候指定分数
zcard key //计算成员个数
zscore key member //计算某个成员的分数
zrank key member //计算成员排名,从低到高
zrevrank key member //计算成员排名,从高到低
zrem key member [member...] //删除成员
zincrby key increnment member //增加成员的分数
zrange key start end [withscores] //从低到高返回指定排名的分数
zrevrange key start end [withscores] //从高到低返回
zrangebyscore key min max [withscores] [limit offset count] //按照分数从低到高返回
zrevrange score key min max [withscores] [limit offset count] //按照分数从高到低返回成员
withscore 代表返回的时候带上成员的分数
...还有求交集,并集等操作
3.应用场景
在集合类型的场景上加入排序就是有序集合的应用场景了。
#####(1)根据好友的“亲密度”排序显示好友列表。
// 用元素的分数(score)表示与好友的亲密度
zadd user:kobe 80 james 90 wade 85 melo 90 paul
// 根据“亲密度”给好友排序
zrevrange user:kobe 0 -1
/**
* 输出:
* 1) "wade"
* 2) "paul"
* 3) "melo"
* 4) "james"
*/
// 增加好友的亲密度
zincrby user:kobe 15 james
// 再次根据“亲密度”给好友排序
zrevrange user:kobe 0 -1
/**
* 输出:
* 1) "james"
* 2) "wade"
* 3) "paul"
* 2) "melo"
*/
//类似的需求还出现在根据文章的阅读量或点赞量对文章列表排序
(2)排行榜
实效性
从排行榜的实效性上划分,主要分为:
- 实时榜:基于当前一段时间内数据的实时更新,进行排行。例如:当前一小时内游戏热度实时榜,当前一小时内明星送花实时榜等
- 历史榜:基于历史一段周期内的数据,进行排行。例如:日榜(今天看昨天的),周榜(上一周的),月榜(上个月的),年榜(上一年的)
业务数据类型
从需要排行的数据类型上划分,主要分为:
- 单类型数据排行榜:是指需要排行的主体不需要区分类型,例如,所有用户积分排行,所有公贡献值排行,所有游戏热度排行等
- 多类型(复合类型)数据排行榜:是指需要排行的主体在排行中要求有类型上的区分,例如:竞技类游戏热度排行、体育类游戏热度排行、MOBA类游戏操作性排行、角色/回合/卡牌三类游戏热度排行等
展示唯度
从榜单的最终展示唯度上划分,主要分为:
- 单唯度:是指选择展示的排行榜就是基于一个唯度下的排行,例如前面提到的MOBA类游戏操作性排行榜,就仅展示所有MOBA类游戏按操作性的评分排行
- 多唯度:是指选择展示的排行榜还有多种唯度供用户选择,仍然以前面的MOBA类游戏为例,唯度除了操作性,还有音效评分排行,难易度评分排行,画面评分排行等。
展示数据量
从需要展示的数据量上划分,主要分为:
- topN数据:只要求展示topN条排行纪录,例如:最火MOBA游戏top20
- 全量数据:要求展示所有数据的排行,例如:所有用户的积分排行
八.项目中哪些地方用到了Redis
数据采集字典表基础数据
最新数据采集值
物联网设备传送byte[]缓存
环境阈值
参考:https://yq.aliyun.com/articles/72666?t=t1
https://www.imooc.com/article/70762
(1)Redis客户端命令行redis-cli操作
https://www.cnblogs.com/kongzhongqijing/p/6867960.html
https://www.runoob.com/redis/redis-commands.html
如何连接redis服务器:redis-cli ip地址 端口号 连接的是集群需要单独配置参数-c
(2)RedisPlus图形化客户端-支持集群的访问
开源地址:https://gitee.com/MaxBill/RedisPlus
下载地址:https://pan.baidu.com/s/1ETwWnEj4rbsE1S3GlYHlWg
九.java整合jedis操作redis
1.添加依赖
<!-- https://mvnrepository.com/artifact/redis.clients/jedis -->
<dependency>
<groupId>redis.clients</groupId>
<artifactId>jedis</artifactId>
<version>2.9.0</version>
</dependency>
2.代码以及指令操作
Hash:
1.java代码
import redis.clients.jedis.Jedis;
import java.util.HashMap;
import java.util.Map;
/**
* Created by admin on 2018/3/12.
*/
public class TestHash {
/**
* Redis hash 是一个string类型的field和value的映射表,hash特别适合用于存储对象。
Redis 中每个 hash 可以存储 232 - 1 键值对(40多亿)
* @param args
*/
public static void main(String[] args) {
Jedis conn = new Jedis("localhost");
conn.hset("student","name","yz");
System.out.println(conn.hget("student","name"));
Map<String,String> studentFields = new HashMap<String,String>();
studentFields.put("score","56");
studentFields.put("addr","gaoxin");
conn.hmset("student",studentFields);//批量添加
System.out.println(conn.hgetAll("student"));//获取键值
System.out.println(conn.hmget("student","score","name"));//批量获取key中field对应的val
conn.hincrByFloat("student","score",1.2);// 同 String
System.out.println(conn.hget("student","score"));
System.out.println(conn.hkeys("student"));//获取所有的key
System.out.println(conn.hvals("student"));//获取所有的val
System.out.println(conn.hlen("student"));//获取长度
System.out.println(conn.hexists("student","name"));//判断是否存在
conn.hdel("student","addr");//删除一个field
System.out.println(conn.hexists("student","addr"));
conn.hsetnx("student","addr","hefei");//不存在 即设置
System.out.println(conn.hget("student","addr"));
System.out.println(conn.type("student"));//hash
}
}
2.cli指令
127.0.0.1:6379> hset user name yz
(integer) 1
127.0.0.1:6379> hget user name
"yz"
127.0.0.1:6379> hmset user sex boy score 86 addr hefei
OK
127.0.0.1:6379> hgetall user------------------
1) "name"
2) "yz"
3) "sex"
4) "boy"
5) "score"
6) "86"
7) "addr"
8) "hefei"
127.0.0.1:6379> hexists user name
(integer) 1
127.0.0.1:6379> hget user name
"yz"
127.0.0.1:6379> hkeys user----------------
1) "name"
2) "sex"
3) "score"
4) "addr"
127.0.0.1:6379> hvals user-----------------
1) "yz"
2) "boy"
3) "86"
4) "hefei"
127.0.0.1:6379> hlen user
(integer) 4
127.0.0.1:6379> hincrbyfloat user score 5.6
"91.599999999999994"
127.0.0.1:6379> hget user score
"91.599999999999994"
127.0.0.1:6379> hmget user name score
1) "yz"
2) "91.599999999999994"
127.0.0.1:6379> hmset user name yz1 score 100
OK
127.0.0.1:6379> hgetall user
1) "name"
2) "yz1"
3) "sex"
4) "boy"
5) "score"
6) "100"
7) "addr"
8) "hefei"
127.0.0.1:6379> hsetnx user name yz--------------------------
(integer) 0
127.0.0.1:6379> hget user name
"yz1"
127.0.0.1:6379>
List:
1.java代码
import redis.clients.jedis.BinaryClient;
import redis.clients.jedis.Jedis;
/**
* Created by admin on 2018/3/12.
*/
public class TestList {
/**
* Redis列表是简单的字符串列表,按照插入顺序排序。你可以添加一个元素到列表的头部(左边)或者尾部(右边)
一个列表最多可以包含 232 - 1 个元素 (4294967295, 每个列表超过40亿个元素)
* @param args
*/
public static void main(String[] args) {
Jedis conn = new Jedis("localhost");
System.out.println(conn.ping());
conn.lpush("list1","yz","wc","xzg"); //像list添加元素
System.out.println(conn.lrange("list1",0,-1));//遍历元素
System.out.println(conn.llen("list1"));//获取元素长度
System.out.println(conn.lindex("list1",1));//获取 下面 1 的元素
System.out.println(conn.lpop("list1"));//左侧弹出元素
System.out.println(conn.rpop("list1"));//右侧弹出元素
conn.lset("list1",0,"hxx");//设置下面0的元素val
conn.rpushx("list1","yz");//如果 list1 存在 则set值
conn.linsert("list1", BinaryClient.LIST_POSITION.AFTER,"yz","wc");//在list1 的 yz 后面插入 wc
conn.lpush("list1","yz"); //头部添加
conn.lrem("list1",2,"yz"); //移除 数量count(=0 所有 >0 从头部(左侧) <) 从尾部)为 yz的元素
conn.ltrim("list1",1,-1);//按下面裁剪集合 返回 范围内的 元素
conn.lpush("list2","cs1","cs2");
System.out.println(conn.lrange("list1",0,-1));//[hxx, xzg, wc]
System.out.println(conn.lrange("list2",0,-1));//[cs2, cs1]
conn.rpoplpush("list1","list2");//集合list1 右侧弹出元素 加入 list2 左侧
System.out.println(conn.lrange("list1",0,-1));//[hxx, xzg]
System.out.println(conn.lrange("list2",0,-1));//[wc, cs2, cs1]
System.out.println(conn.type("list1"));
}
}
2.cli指令
C:\redis>redis-cli
127.0.0.1:6379> lpush list yz
(integer) 1
127.0.0.1:6379> lpush list zwl xzg hxx pc wc zty
(integer) 7
127.0.0.1:6379> lindex list 0----------
"zty"
127.0.0.1:6379> llen list------------
(integer) 7
127.0.0.1:6379> lpop list
"zty"
127.0.0.1:6379> lindex list 0
"wc"
127.0.0.1:6379> rpop list
"yz"
127.0.0.1:6379> rpush list yz
(integer) 6
127.0.0.1:6379> lpush list xdg
(integer) 7
127.0.0.1:6379> lrange list 0 6
1) "xdg"
2) "wc"
3) "pc"
4) "hxx"
5) "xzg"
6) "zwl"
7) "yz"
127.0.0.1:6379> lset list 0 cs-----------
OK
127.0.0.1:6379> lrange list 0 6
1) "cs"
2) "wc"
3) "pc"
4) "hxx"
5) "xzg"
6) "zwl"
7) "yz"
127.0.0.1:6379> linsert list before yz yzq----------
(integer) 8
127.0.0.1:6379> lrange list 0 7
1) "cs"
2) "wc"
3) "pc"
4) "hxx"
5) "xzg"
6) "zwl"
7) "yzq"
8) "yz"
127.0.0.1:6379> lpop list
"cs"
127.0.0.1:6379> lrem list 1 cs------------
(integer) 0
127.0.0.1:6379> lrem list 1 wc
(integer) 1
127.0.0.1:6379> llen list
(integer) 6
127.0.0.1:6379> lrange list 0 6
1) "pc"
2) "hxx"
3) "xzg"
4) "zwl"
5) "yzq"
6) "yz"
127.0.0.1:6379> ltrim list 0 2-------------
OK
127.0.0.1:6379> lrange list 0 6
1) "pc"
2) "hxx"
3) "xzg"
Set:
1.java代码
import redis.clients.jedis.Jedis;
/**
* Created by admin on 2018/3/13.
*/
public class TestSet {
/**
* Redis 的 Set 是 String 类型的无序集合。集合成员是唯一的,这就意味着集合中不能出现重复的数据。
Redis 中集合是通过哈希表实现的,所以添加,删除,查找的复杂度都是 O(1)。
集合中最大的成员数为 232 - 1 (4294967295, 每个集合可存储40多亿个成员)。
* @param args
*/
public static void main(String[] args) {
Jedis conn = new Jedis("localhost");
System.out.println(conn.ping());
conn.sadd("set1","yz","zwl","xzg","hxx","xzg"); //像集合添加元素
System.out.println(conn.smembers("set1"));//遍历所有元素
System.out.println(conn.scard("set1"));//获取集合元素个数
System.out.println(conn.sismember("set1","hxx"));//判断是否是集合元素
System.out.println(conn.spop("set1"));//随机弹出一个元素
System.out.println(conn.srandmember("set1",2));//随机返回 2 个元素 并不会从集合中移除
System.out.println(conn.srem("set1","yz","zwl"));//移除元素
conn.sadd("set2","hxx","yz","zwl","xzg");
System.out.println(conn.sinter("set1","set2"));//求两个集合的交集
System.out.println(conn.sinterstore("set3","set1","set2"));//求两个集合的交集 并存放到set3
System.out.println(conn.smembers("set3"));
System.out.println(conn.sdiff("set1","set2"));//求两个集合的差集 同时也存在 conn.sdiffstore()
System.out.println(conn.sunion("set1","set2"));//求两个集合的并集 同时也存在 conn.sunionstore()
System.out.println(conn.smove("set2","set1","yz"));//将yz 从 set2 移动dao set1 同时set2 中yz 移除
System.out.println(conn.type("set1"));
}
}
2.cli指令
C:\redis>redis-cli
127.0.0.1:6379> sadd set yz zwl xuzg hxx zty wc pc
(integer) 7
127.0.0.1:6379> smembers set ------------
1) "xuzg"
2) "zwl"
3) "yz"
4) "hxx"
5) "wc"
6) "zty"
7) "pc"
127.0.0.1:6379> scard set ----------------
(integer) 7
127.0.0.1:6379> sismember set tz------------
(integer) 0
127.0.0.1:6379> spop set
"pc"
127.0.0.1:6379> spop set
"xuzg"
127.0.0.1:6379> srandmember set 3---------
1) "yz"
2) "zty"
3) "zwl"
127.0.0.1:6379> srandmember set 3
1) "wc"
2) "zty"
3) "zwl"
127.0.0.1:6379> srem wc zty zwl
(integer) 0
127.0.0.1:6379> srem set wc zty
(integer) 2
127.0.0.1:6379> smembers set
1) "yz"
2) "hxx"
3) "zwl"
127.0.0.1:6379> sadd set2 yz zwl
(integer) 2
127.0.0.1:6379> sdiff set set2 --------------
1) "hxx"
127.0.0.1:6379> sdiffstore set3 set set2-------------
(integer) 1
127.0.0.1:6379> smembers set3
1) "hxx"
127.0.0.1:6379> sinter set set2----
1) "yz"
2) "zwl"
127.0.0.1:6379> sinterstore set 3 set set2---------------
(integer) 0
127.0.0.1:6379> sinterstore set3 set set2
(integer) 0
127.0.0.1:6379> smembers set2
1) "yz"
2) "zwl"
127.0.0.1:6379> sinterstore set4 set set2
(integer) 0
127.0.0.1:6379> sunion set set2-------------
1) "yz"
2) "zwl"
127.0.0.1:6379> smembers set
(empty list or set)
127.0.0.1:6379> smove set2 set yz-----------------
(integer) 1
127.0.0.1:6379> smembers set
1) "yz"
127.0.0.1:6379> sinterstore set4 set set2
(integer) 0
String:
1.java代码
import redis.clients.jedis.Jedis;
/**
* Created by admin on 2018/3/12.
*/
public class TestString {
/**
* Redis 字符串数据类型的相关命令用于管理 redis 字符串值
* @param args
*/
public static void main(String [] args) {
Jedis conn = new Jedis("localhost");
System.out.println(conn.ping());//pang 代表链接成功
conn.set("test","123");//set key test val 123
System.out.println(conn.get("test"));//get key
System.out.println(conn.exists("test"));// key是否存在
System.out.println(conn.strlen("test"));//返回key的长度
System.out.println(conn.getrange("test",0,-1));//返回截取字符串长度 0 -1 截取全部
System.out.println(conn.getrange("test",1,2));
System.out.println(conn.append("test","appendStr"));//追加
System.out.println(conn.get("test"));
conn.rename("test","test_new");//重命名
System.out.println(conn.exists("test"));
conn.mset("key1","val1","key2","val2");//批量插入
System.out.println(conn.mget("key1","key2"));//批量取出
System.out.println(conn.del("key1"));//删除
System.out.println(conn.exists("key1"));
System.out.println(conn.getSet("key2","2"));//取出旧值 并set新值
System.out.println(conn.incr("key2")); //自增1 要求数值类型
System.out.println(conn.incrBy("key2",5));//自增5 要求数值类型
System.out.println(conn.decr("key2"));//自减1 要求数值类型
System.out.println(conn.decrBy("key2",5));
System.out.println(conn.incrByFloat("key2",1.1));//增加浮点类型
System.out.println(conn.setnx("key2","existVal"));//返回0 只有在key不存在的时候才设置
System.out.println(conn.get("key2"));// 3.1
System.out.println(conn.msetnx("key2","exists1","key3","exists2"));//只有key都不存在的时候才设置
System.out.println(conn.mget("key2","key3"));// null
conn.setex("key4",3,"3 seconds is no Val");//设置key 3 秒后失效
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(conn.get("key4"));// 3 seconds is no Val
conn.psetex("key5",2000,"2000 milliseconds is no Val ");//设置秒数单位为毫秒
try {
Thread.sleep(3000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(conn.get("key5"));//null
conn.set("key6","123456789");
conn.setrange("key6",3,"abcdefg"); //从第三位开始 将值覆盖 下标从0 开始
System.out.println(conn.get("key6"));//123abcdefg
System.out.println(conn.type("key6"));//返回数据类型 string
}
}
2.cli指令
C:\redis>redis-cli
127.0.0.1:6379> ping
PONG
127.0.0.1:6379> set mykey cs
OK
127.0.0.1:6379> get mykey
"cs"
127.0.0.1:6379> type mykey
string
127.0.0.1:6379> rename mykey newmykey ---------------
OK
127.0.0.1:6379> get newmykey
"cs"
127.0.0.1:6379> exists newmykey --------------
(integer) 1
127.0.0.1:6379> dump newmykey----------------
"\x00\x02cs\a\x00\x99\x9e\xfd\x18;\xb4\x81)"
127.0.0.1:6379> exists newmykey
(integer) 1
127.0.0.1:6379> del newmykey
(integer) 1
127.0.0.1:6379> exists newmykey
(integer) 0
127.0.0.1:6379> set mykey key
OK
127.0.0.1:6379> get mykey
"key"
127.0.0.1:6379> getrange mykey 0 3--------------------
"key"
127.0.0.1:6379> getrange mykey 0 1
"ke"
127.0.0.1:6379> getset mykey newval------------
"key"
127.0.0.1:6379> get mykey
"newval"
127.0.0.1:6379> set yourkey val2
OK
127.0.0.1:6379> mget mykey yourkey
1) "newval"
2) "val2"
127.0.0.1:6379> strlen mykey---------------
(integer) 6
127.0.0.1:6379> mset mykey yourkey 1 2
OK
127.0.0.1:6379> mget mykey yourkey
1) "yourkey"
2) "val2"
127.0.0.1:6379> mset mykey old1 yourkey old2
OK
127.0.0.1:6379> mget mykey yourkey
1) "old1"
2) "old2"
127.0.0.1:6379> decr mykey-----------
(error) ERR value is not an integer or out of range
127.0.0.1:6379> set mykey 1
OK
127.0.0.1:6379> decr mykey
(integer) 0
127.0.0.1:6379> incr mykey------------
(integer) 1
127.0.0.1:6379> incrby mykey 4
(integer) 5
127.0.0.1:6379> get mykey
"5"
127.0.0.1:6379> incrbyfloat mykey 1.1------------
"6.1"
127.0.0.1:6379> get yourkey
"old2"
127.0.0.1:6379> append yourkey 11------------------
(integer) 6
127.0.0.1:6379> get yourkey
"old211"
ZSet:
1.java代码
import redis.clients.jedis.Jedis;
import redis.clients.jedis.Tuple;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;
/**
* Created by admin on 2018/3/13.
*/
public class TestZSet {
/**
* Redis 有序集合和集合一样也是string类型元素的集合,且不允许重复的成员。
不同的是每个元素都会关联一个double类型的分数。redis正是通过分数来为集合中的成员进行从小到大的排序。
有序集合的成员是唯一的,但分数(score)却可以重复。
集合是通过哈希表实现的,所以添加,删除,查找的复杂度都是O(1)。 集合中最大的成员数为 232 - 1 (4294967295, 每个集合可存储40多亿个成员)。
* @param args
*/
public static void main(String[] args) {
Jedis conn = new Jedis("localhost");
System.out.println(conn.ping());
Map<String,Double> members = new HashMap<String,Double>();
members.put("yz",12.0);
members.put("zwl",67.5);
members.put("xzg",34.0);
conn.zadd("zset1",members);//添加元素
System.out.println(conn.zcard("zset1"));//获取集合元素个数
System.out.println(conn.zrange("zset1",0,-1));//按照下标起始终止遍历元素
System.out.println(conn.zrangeByScore("zset1",30,60));//按照分数起始终止遍历元素
Set<Tuple> res0 = conn.zrangeByScoreWithScores("zset1",30,60);//按照分数起始终止遍历元素 返回 field score
for(Tuple temp:res0){
System.out.println(temp.getElement()+" : "+temp.getScore());
}
System.out.println(conn.zrevrange("zset1",0,-1));//按照下标起始终止倒序遍历元素
System.out.println(conn.zrevrangeByScore("zset1",60,0));//按照分数起始终止倒序遍历元素
System.out.println(conn.zscore("zset1","yz"));//获取元素score值
System.out.println(conn.zcount("zset1",0,60));//获取元素分数区间的元素
System.out.println(conn.zrank("zset1","yz"));//获取元素下标
System.out.println(conn.zrevrank("zset1","yz"));//倒序获取元素下标
System.out.println(conn.zrem("zset1","yz","zwl"));//删除元素
System.out.println(conn.zremrangeByRank("zset3",0,-1));//删除元素通过下标范围
System.out.println(conn.zremrangeByScore("zset4",0,10));//删除元素通过分数范围
System.out.println(conn.zrange("zset1",0,-1));
Map<String,Double> members2 = new HashMap<String,Double>();
members2.put("yz",36.1);
members2.put("zwl",12.5);
members2.put("xzg",24.0);
conn.zadd("zset2",members2);//添加元素
System.out.println( conn.zincrby("zset1",1,"yz"));//增加指定分数
Set<Tuple> rs = conn.zrangeWithScores("zset1",0,-1);
for(Tuple temp:rs){
System.out.println(temp.getElement()+" : "+temp.getScore());
}
System.out.println("===================================");
Set<Tuple> rs2 = conn.zrangeWithScores("zset2",0,-1);
for(Tuple temp:rs2){
System.out.println(temp.getElement()+" : "+temp.getScore());
}
System.out.println("===================================");
conn.zinterstore("zset3","zset1","zset2");
Set<Tuple> rs3 = conn.zrangeWithScores("zset3",0,-1);
for(Tuple temp:rs3){
System.out.println(temp.getElement()+" : "+temp.getScore());
}
/**
* ZUNIONSTORE destination numkeys key [key ...] [WEIGHTS weight [weight ...]] [AGGREGATE SUM|MIN|MAX]
计算给定的一个或多个有序集的并集,其中给定 key 的数量必须以 numkeys 参数指定,并将该并集(结果集)储存到 destination 。
默认情况下,结果集中某个成员的 score 值是所有给定集下该成员 score 值之 和 。
WEIGHTS
使用 WEIGHTS 选项,你可以为 每个 给定有序集 分别 指定一个乘法因子(multiplication factor),
每个给定有序集的所有成员的 score 值在传递给聚合函数(aggregation function)之前都要先乘以该有序集的因子。
如果没有指定 WEIGHTS 选项,乘法因子默认设置为 1 。
AGGREGATE
使用 AGGREGATE 选项,你可以指定并集的结果集的聚合方式。
默认使用的参数 SUM ,可以将所有集合中某个成员的 score 值之 和 作为结果集中该成员的 score 值;
使用参数 MIN ,可以将所有集合中某个成员的 最小 score 值作为结果集中该成员的 score 值;
而参数 MAX 则是将所有集合中某个成员的 最大 score 值作为结果集中该成员的 score 值。
*/
conn.zunionstore("zset4","zset1","zset2");
Set<Tuple> rs4 = conn.zrangeWithScores("zset4",0,-1);
for(Tuple temp:rs4){
System.out.println(temp.getElement()+" : "+temp.getScore());
}
System.out.println(conn.type("zset1"));//zset
}
}
2.cli指令
127.0.0.1:6379> zadd zset 100 yz 21 zwl 32 wc 4 pv 11 hxx 15 xzg
(integer) 6
127.0.0.1:6379> zrange zset 0 -1
1) "pv"
2) "hxx"
3) "xzg"
4) "zwl"
5) "wc"
6) "yz"
127.0.0.1:6379> zrangebyscore zset 0 77 withscores
1) "pv"
2) "4"
3) "hxx"
4) "11"
5) "xzg"
6) "15"
7) "zwl"
8) "21"
9) "wc"
10) "32"
127.0.0.1:6379> zcount zset 0 77
(integer) 5
127.0.0.1:6379> zlexcount zset [a [g
(integer) 0
127.0.0.1:6379> zrange zset 0 3
1) "pv"
2) "hxx"
3) "xzg"
4) "zwl"
127.0.0.1:6379> zrevrange zset 0 3
1) "yz"
2) "wc"
3) "zwl"
4) "xzg"
127.0.0.1:6379> zrange zset 0 -1
1) "pv"
2) "hxx"
3) "xzg"
4) "zwl"
5) "wc"
6) "yz"
127.0.0.1:6379> zrevrangebyscore zset 10 20 withscores
(empty list or set)
127.0.0.1:6379> zrevrangebylex zset [a [g
(empty list or set)
127.0.0.1:6379> zrank zset pv
(integer) 0
127.0.0.1:6379> zrank zset wc
(integer) 4
127.0.0.1:6379> zscore zset wc
"32"
127.0.0.1:6379> zcard zset
(integer) 6
127.0.0.1:6379> zrem zset wc
(integer) 1
127.0.0.1:6379> zincrby zset zwl 50
(error) ERR value is not a valid float
127.0.0.1:6379> zrange zset 0 -1
1) "pv"
2) "hxx"
3) "xzg"
4) "zwl"
5) "yz"
127.0.0.1:6379> zrange zset 0 -1 withscores
1) "pv"
2) "4"
3) "hxx"
4) "11"
5) "xzg"
6) "15"
7) "zwl"
8) "21"
9) "yz"
10) "100"
127.0.0.1:6379> zincrby zset 50 zwl
"71"
127.0.0.1:6379> zadd zset1 10 pv 1 yz
(integer) 2
127.0.0.1:6379> zinterstore zset3 2 zset zset1
(integer) 2
127.0.0.1:6379> zrange zset3 0 -1
1) "pv"
2) "yz"
127.0.0.1:6379> zrange zset3 0 -1 withscores
1) "pv"
2) "14"
3) "yz"
4) "101"
127.0.0.1:6379> zunionstore zset4 2 zset zset1
(integer) 5
127.0.0.1:6379> zrange zset4 0 -1
1) "hxx"
2) "pv"
3) "xzg"
4) "zwl"
5) "yz"
127.0.0.1:6379> zrange zet4 0 -1 withscores
(empty list or set)