Nosql
现在处于大数据时代.
大数据一般的数据库无法进行分析处理的
大数据时代的3V:主要是描述问题的
1.海量Voume
2.多样Variety
3.实时Velocity
大数据时代的3高,主要是对程序的要求
1.高并发
2.高可扩
3.高性能(保证用户体验和性能)
KV键值对:
文档形数据库:
MongoDB(一般必须要掌握)
ConthDB
列存储数据库
图关系数据库
Redis是什么?
Redis(Remote Dictionary Server) ,远超字典服务,开源的,用c语言编写,支持网络,基于内存可持久化的日志型,Key-Value数据库.并提供多种语言的API.
redis会周期性的把更新的数据写入磁盘或者修改操作写入追加的记录文件,并且在此基础上实现了master-slave(主从)同步
免费和开源!当下最热门的NoSql技术之一,也被称为结构化数据库.
Redis能干嘛?
1.内存存储,持久化,内存中是断电即失,所以持久化很重要(rdb,aof)
2.效率高,可以用于高速缓存
3.发布订阅系统
4.地图信息分析
5.计时器,计数器(浏览量等)
特性
1.多样的数据类型
2.持久化
3.集群
4.事务
.......
学习中需要用到的东西
redis中文:http://redis.cn/
redis推荐都是再linux服务器上搭建的,基于linux学习
redis官网:https://redis.io/
redis中文官网:http://redis.cn/
linux安装redis,我将redis安装在阿里云服务器的centos7.x系统上,用xshell6连接服务器,xftp6传送数据
先下载redis6.0 用xftp将安装包放入linux系统中(我放在opt目录) 运行安装包
redis6需要gcc5.3以上版本
centos7还是4.8.5
安装scl源
yum install centos-release-scl scl-utils-build
安装gcc9
yum -y install devtoolset-9-gcc devtoolset-9-gcc-c++ devtoolset-9-binutils
scl enable devtoolset-9 bash
gcc -v查看版本
解压源码包
tar zxvf redis-6.0.5.tar.gz
然后全程 y
配置文件在 /opt/redis-6.0.5
我们备份配置文件 到/home中
然后修改/home中的redis-conf
vim redis-conf
requirepass xxxxxxxxxx # 设置访问密码
注释掉 bind 127.0.0.1 # 设置redis为任何ip都可访问,如需设置指定ip,则添加bind
protected-mode no # 设置为no,否则不能保证全网段进行访问
daemonize yes # 设置为yes,保证以守护进程的方式运行redis
运行文件在/opt/redis-6.0.5/src中
我们复制redis-server,redis-cli到/usr/local/bin中
然后输入redis-server /home/redis.conf启动服务
我这里还没有修改ip,只能本机访问
用redis-cli -p 6379测试连接
如果设置了密码,输入 auth [密码] 来验证密码
shutdown关闭连接
exit退出
redis自带的压力测试工具
//测试:100个并发连接 100000请求
redis-benchmark -h localhost -p 6379 -c 100 -n 100000
set请求测试
对10w个请求进行测试
100个并发客户端
每次写入3个字节
只有1台服务器来处理这些请求,单机性能
每秒平均处理82236.84次请求
redis默认16个数据库
默认使用的是第0个
127.0.0.1:6379> select 3 //切换到第3个数据库
OK
127.0.0.1:6379[3]> DBSIZE //返回当前数据库的 key 的数量
(integer) 0
查看所以的key: keys *
清除当前的数据库: flushdb
清除全部数据库的内容: flushall
Redis是单线程的!
明白Redis是很快的,官方表示,Redis是基于内存操作的,CPU不是Redis性能瓶颈
Redis的瓶颈是根据机器的内存和网络带宽,既然可以使用单线程来实现,就使用单线程了.
Redis是c语言写的,官方提供的数据为100000+的QPS,完全不必同样是使用key-vale的Memecache查!
Redis为什么单线程还这这么快?
1.误区:高性能的服务器一定是多线程的
2.误区2:多线程(CPU上下文会切换!)一定比单线程效率高!
CPU>内存>硬盘的速度
核心:redis是将所以的数据全部放在内存中的,所以用单线程操作就是效率最高的,多线程(cpu上下切换:耗时的操作!)对于内存系统来说,若干没有上下文切换效率就是最高,多次读写都在一个cpu上的,在内存情况下,就是最佳方案
127.0.0.1:6379> keys * //获得当前数据库的所以key
1) "id"
2) "age"
3) "name"
127.0.0.1:6379> exists name //判断name这个key是否存在
(integer) 1
127.0.0.1:6379> exists name1
(integer) 0
127.0.0.1:6379> exists age
(integer) 1
127.0.0.1:6379> move name 1 //移除name这个key
(integer) 1
127.0.0.1:6379> exists name
(integer) 0
127.0.0.1:6379> keys *
1) "id"
2) "age"
127.0.0.1:6379> set name wangtao //设置name-wangtao 这个key
OK
127.0.0.1:6379> keys *
1) "id"
2) "age"
3) "name"
127.0.0.1:6379> get name //获得name这个key的value
"wangtao"
127.0.0.1:6379> expire name 10 //设置name这个key在10秒后删除
(integer) 1
127.0.0.1:6379> ttl name //获得name这个key还能存活的时间
(integer) 1 //还能存活1秒
127.0.0.1:6379> ttl name
(integer) -2 //已经不在数据库中
127.0.0.1:6379> get name
(nil)
127.0.0.1:6379> ttl age
(integer) -1 //一直存在,没有设置key的存活时间
127.0.0.1:6379> ttl ag
(integer) -2
127.0.0.1:6379>
查看key的类型:
127.0.0.1:6379> keys *
1) "id"
2) "age"
127.0.0.1:6379> type age
string
127.0.0.1:6379> type id
string
ProcessOn:https://www.processon.com/mindmap/5f08b50cf346fb3fdc64a43a
string 字符串
127.0.0.1:6379> clear
127.0.0.1:6379> set key1 v1 //设置值
OK
127.0.0.1:6379> get key1 //获得值
"v1"
127.0.0.1:6379> keys * //获得所有key
1) "key1"
127.0.0.1:6379> exists key1 //判断某个key是否存在
(integer) 1
127.0.0.1:6379> append key1 "abc" //追加字符串,如果当前key不存在,就相当于setkey
(integer) 5
127.0.0.1:6379> get key1
"v1abc"
127.0.0.1:6379> strlen key1
(integer) 5
127.0.0.1:6379> append key1 "kuangshen"
(integer) 14
127.0.0.1:6379> strlen kye1 //获得长度
(integer) 0
127.0.0.1:6379> strlen key1
(integer) 14
127.0.0.1:6379> get key1
"v1abckuangshen"
计数
127.0.0.1:6379> set views 0
OK
127.0.0.1:6379> get views
"0"
127.0.0.1:6379> incr views //views 增1
(integer) 1
127.0.0.1:6379> incr views
(integer) 2
127.0.0.1:6379> decr views
(integer) 1
127.0.0.1:6379> incr views //views 减1
(integer) 2
127.0.0.1:6379> get views
"2"
127.0.0.1:6379> incr views
(integer) 3
127.0.0.1:6379> incrby views 10 //views 增加10
(integer) 13
127.0.0.1:6379> decrby views 5 //views 减少10
(integer) 8
字符串范围截取 range
127.0.0.1:6379> set key1 "hellowangtao"
OK
127.0.0.1:6379> get key1
"hellowangtao"
127.0.0.1:6379> getrange key1 0 3 //获得[0,3]的字符串片段
"hell"
127.0.0.1:6379> getrange key1 0 -1 //获得所有字符串片段
"hellowangtao"
字符替换
127.0.0.1:6379> set key2 abcdefg
OK
127.0.0.1:6379> get key2
"abcdefg"
127.0.0.1:6379> setrange key2 1 xx 从1位置开始 将后面的字符串替换为xx,替换的长度和xx相同
(integer) 7
127.0.0.1:6379> get key2
"axxdefg"
设置key-value并设置过期时间
127.0.0.1:6379> setex key3 30 123abc
OK
127.0.0.1:6379> ttl key3
(integer) 23
不存在才就设置(在分布式锁中常常使用)
127.0.0.1:6379> set key1 3
OK
127.0.0.1:6379> keys *
1) "key1"
127.0.0.1:6379> setnx key1 4
(integer) 0
127.0.0.1:6379> setnx key2 5
(integer) 1
127.0.0.1:6379> keys *
1) "key1"
2) "key2"
127.0.0.1:6379> get key1
"3"
127.0.0.1:6379> get key2
"5"
批量设置key-value
127.0.0.1:6379> keys *
(empty array)
127.0.0.1:6379> mset k1 v1 k2 v2 k3 v3
OK
127.0.0.1:6379> get k1
"v1"
127.0.0.1:6379> get k2
"v2"
127.0.0.1:6379> get k3
"v3"
127.0.0.1:6379> keys *
1) "k2"
2) "k1"
3) "k3"
批量获得key-value
127.0.0.1:6379> mget k1 k2 k3
1) "v1"
2) "v2"
3) "v3"
同时设置,如果一个失败,则都失败(保证原子性)
127.0.0.1:6379> get k1
"v1"
127.0.0.1:6379> msetnx k1 gg k4 v4
(integer) 0
127.0.0.1:6379> get k1
"v1"
127.0.0.1:6379> get k4
(nil)
设置对象
本质还是字符串的操作
127.0.0.1:6379> set user:1 {name:wangtao,age:22}
OK
127.0.0.1:6379> get user:1
"{name:wangtao,age:22}"
127.0.0.1:6379> mset user:2:name zhangsan user:2:age 19
OK
127.0.0.1:6379> mget user:2:name user:2:age
1) "zhangsan"
2) "19"
//user:{id}:{filed},这种设计在redis中完全ok
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 mongdb//如果存在,获取原来的值,再设置新的值
"redis"
127.0.0.1:6379> get db
"mongdb"
使用场景:value除了字符串还可以是数字
在redis里面,我们可以把list玩成栈,队列,阻塞队列
所有的list都是以l开头的,redis不区分大小写命令
push 插入元素
127.0.0.1:6379> keys *
(empty array)
127.0.0.1:6379> lpush list one //将一个值从头部插入
(integer) 1
127.0.0.1:6379> lpush list two
(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) "two"
3) "one"
127.0.0.1:6379> lrange list 0 1 //按区间获得list中的值
1) "three"
2) "two"
127.0.0.1:6379> rpush list abc //将一个值从尾部插入
(integer) 4
127.0.0.1:6379> lrange list 0 -1
1) "three"
2) "two"
3) "one"
4) "abc"
pop 弹出元素
127.0.0.1:6379> lrange list 0 -1
1) "three"
2) "two"
3) "one"
127.0.0.1:6379> lpop list //移除第一个元素
"three"
127.0.0.1:6379> lrange list 0 -1
1) "two"
2) "one"
127.0.0.1:6379> rpop list //移除list最后一个元素
"one"
127.0.0.1:6379> lrange list 0 -1
1) "two"
通过下标获得值
127.0.0.1:6379> lrange list 0 -1
1) "c"
2) "b"
3) "a"
4) "two"
127.0.0.1:6379> lindex list 1
"b"
127.0.0.1:6379> lindex list 0
"c"
获得list长度
127.0.0.1:6379> llen list
(integer) 4
移除指定的值
127.0.0.1:6379> lrange list 0 -1
1) "a"
2) "c"
3) "b"
4) "a"
5) "two"
127.0.0.1:6379> lrem list 1 a //移除1个指定的值,从头部开始
(integer) 1
127.0.0.1:6379> lrange list 0 -1
1) "c"
2) "b"
3) "a"
4) "two"
127.0.0.1:6379> lrange list 0 -1
1) "a"
2) "c"
3) "b"
4) "a"
5) "two"
127.0.0.1:6379> lrem list 2 a //移除2个a
(integer) 2
127.0.0.1:6379> lrange list 0 -1
1) "c"
2) "b"
3) "two"
只保留指定的值 ltrim xx a b 除了[a,b]区间的元素,别的元素全部删除
127.0.0.1:6379> lrange mylist 0 -1
1) "hello"
2) "hello1"
3) "hello2"
4) "hello3"
127.0.0.1:6379> ltrim mylist 1 2
OK
127.0.0.1:6379> lrange mylist 0 -1
1) "hello1"
2) "hello2"
127.0.0.1:6379>
lpoplpush 移除列表最后的一个元素,并将其移动到新的列表中
127.0.0.1:6379> lpush mylist "hello"
(integer) 1
127.0.0.1:6379> lpush mylist "hello1"
(integer) 2
127.0.0.1:6379> lpush mylist "hello2"
(integer) 3
127.0.0.1:6379> rpoplpush mylist mylist2
"hello"
127.0.0.1:6379> lrange mylist 0 -1
1) "hello2"
2) "hello1"
127.0.0.1:6379> lrange mylist2 0 -1
1) "hello"
127.0.0.1:6379>
修改指定下标的元素,若这个位置没有元素,则返回(error) ERR no such key
127.0.0.1:6379> lrange list 0 -1
1) "bb"
2) "aa"
127.0.0.1:6379> lset list 0 cc
OK
127.0.0.1:6379> lrange list 0 -1
1) "cc"
2) "aa"
在指定元素前/后插入一个指定的值
127.0.0.1:6379> lrange list 0 -1
1) "aa"
2) "bb"
3) "cc"
127.0.0.1:6379> linsert list before cc xx //在cc前插入xx
(integer) 4
127.0.0.1:6379> lrange list 0 -1
1) "aa"
2) "bb"
3) "xx"
4) "cc"
127.0.0.1:6379> linsert list after bb yy //在bb后面插入yy
(integer) 5
127.0.0.1:6379> lrange list 0 -1
1) "aa"
2) "bb"
3) "yy"
4) "xx"
5) "cc"
127.0.0.1:6379>
小结
消息队列(Lpush,Rpop) ,栈(Lpush,Lpop)
set中的值是不重复的
sadd 插入值
127.0.0.1:6379> sadd myset aa //插入1个值,若插入成功,返回1,反之返回0
(integer) 1
127.0.0.1:6379> sadd myset bb
(integer) 1
127.0.0.1:6379> sadd mysey cc
(integer) 1
127.0.0.1:6379> smembers myset //输出set所有的值
1) "bb"
2) "aa"
127.0.0.1:6379> sadd myset aa //重复插入,返回0
(integer) 0
127.0.0.1:6379> sismember myset bb //判断set中是否有bb这个元素,1表示有,0表示没有
(integer) 1
127.0.0.1:6379> sismember myset dd
(integer) 0
127.0.0.1:6379>
获取set的元素个数
127.0.0.1:6379> scard myset
(integer) 2
移除元素
127.0.0.1:6379> srem myset bb
(integer) 1
127.0.0.1:6379> smembers myset
1) "aa"
随机获得一个元素
127.0.0.1:6379> smembers myset
1) "aa"
2) "dd"
3) "cc"
127.0.0.1:6379> srandmember myset
"cc"
127.0.0.1:6379> srandmember myset
"dd"
127.0.0.1:6379> srandmember myset
"dd"
127.0.0.1:6379> srandmember myset
"aa"
127.0.0.1:6379> srandmember myset
"cc"
随机删除一个元素
127.0.0.1:6379> spop myset 1
1) "aa"
将一个指定的值,移动到另外一个set中
127.0.0.1:6379> smembers myset
1) "bb"
2) "aa"
3) "cc"
127.0.0.1:6379> smembers myset2
1) "11"
2) "22"
3) "33"
127.0.0.1:6379> smove myset myset2 aa
(integer) 1
127.0.0.1:6379> smembers myset
1) "bb"
2) "cc"
127.0.0.1:6379> smembers myset2
1) "aa"
2) "22"
3) "33"
4) "11"
微博,B站,共同关注(并集)
数学集合:
127.0.0.1:6379> smembers myset
1) "bb"
2) "aa"
3) "tom"
127.0.0.1:6379> smembers myset2
1) "22"
2) "tom"
3) "11"
127.0.0.1:6379> sdiff myset myset2 //差集,myset有myset2没有的
1) "aa"
2) "bb"
127.0.0.1:6379> sinter myset myset2//交集
1) "tom"
127.0.0.1:6379> sunion myset myset2//并集
1) "22"
2) "tom"
3) "bb"
4) "aa"
5) "11"
微博,a用户将所有关注的人放在一个set集合中,将它的粉丝也放在一个集合中
共同关注,共同爱好,二度好友,推荐好友
map集合,key-map 这个值是一个map集合,本质和string类型没有太大区别,还是一个简单的key-value
127.0.0.1:6379> hset myhash field1 wangtao //set一个具体的key-value
(integer) 1
127.0.0.1:6379> hget myhash field1 //获取一个字段值
"wangtao"
127.0.0.1:6379> hmset myhash field1 aa field2 bb //set多个具体的key-value
OK
127.0.0.1:6379> hmget myhash field field2 //获取多个字段值
1) (nil)
2) "bb"
127.0.0.1:6379> hmget myhash field1 field2
1) "aa"
2) "bb"
127.0.0.1:6379> hgetall myhash //获取全部数据
1) "field1"
2) "aa"
3) "field2"
4) "bb"
127.0.0.1:6379> hdel myhash field1//删除指定的key-value
(integer) 1
127.0.0.1:6379> hgetall myhash
1) "field2"
2) "bb"
127.0.0.1:6379> hgetall myhash
1) "field2"
2) "bb"
3) "field1"
4) "aa"
5) "field3"
6) "cc"
127.0.0.1:6379> hlen myhash//获取字段长度
(integer) 3
127.0.0.1:6379> hexists myhash field1//判断指定字段是否存在
(integer) 1
127.0.0.1:6379> hexists myhash field4
(integer) 0
只获得所有的key/value
127.0.0.1:6379> hkeys myhash
1) "field2"
2) "field1"
3) "field3"
127.0.0.1:6379> hvals myhash
1) "bb"
2) "aa"
3) "cc"
对一个value为数的字段进行+/-
127.0.0.1:6379> hset myhash field5 3
(integer) 1
127.0.0.1:6379> hincrby myhash field5 3//指定增量
(integer) 6
127.0.0.1:6379> hincrby myhash field5 -1
(integer) 5
127.0.0.1:6379> hsetnx myhash field3 xx//不存在才设置
(integer) 0
127.0.0.1:6379> hsetnx myhash field4 vv
(integer) 1
hash变更的数据,经常变动的信息,更适合对象的存储,string更适合字符串
redis 有序集合zset和集合set一样也是string类型元素的集合,且不允许重复的成员
不同的是 zset 的每个元素都会关联一个分数(分数可以重复),redis 通过分数来为集合中 的成员进行从小到大的排序.
127.0.0.1:6379> zadd myzset 1 one
(integer) 1
127.0.0.1:6379> zadd myzset 2 two
(integer) 1
127.0.0.1:6379> zadd myzset 3 three 4 four
(integer) 2
127.0.0.1:6379> zrange myzset 0 -1
1) "one"
2) "two"
3) "three"
4) "four"
排序
127.0.0.1:6379> zadd salary 2500 wangtao
(integer) 1
127.0.0.1:6379> zadd salary 6500 zhangsan
(integer) 1
127.0.0.1:6379> zadd salary 1500 lisi
(integer) 1
127.0.0.1:6379> zrangebyscore salary -inf +inf//升序
1) "lisi"
2) "wangtao"
3) "zhangsan"
127.0.0.1:6379> zrevrangebyscore salary +inf -inf//降序
1) "zhangsan"
2) "wangtao"
3) "lisi"
127.0.0.1:6379> zrangebyscore salary -inf +inf withscores//查询并显示分数
1) "lisi"
2) "1500"
3) "wangtao"
4) "2500"
5) "zhangsan"
6) "6500"
删除一个元素
127.0.0.1:6379> zrangebyscore salary -inf +inf
1) "zhangsan"
2) "wangtao"
3) "lisi"
127.0.0.1:6379> zrem salary lisi
(integer) 1
127.0.0.1:6379> zrange salary 0 -1
1) "zhangsan"
2) "wangtao"
显示集合元素数目
zcard [zset] 显示zset元素数目
127.0.0.1:6379> zcard salary
(integer) 2
获取区间范围内元素数目
zcount [zset] [score1] [score2] 获取[score1,sorce2]区间的元素数目
127.0.0.1:6379> zcount salary -inf +inf
(integer) 2
127.0.0.1:6379> zcount salary 3000 4000
(integer) 1
我们工作中有需要,就去看官方文档
案例思路:set 排序,存储班级成绩表,工资表排序
带权重执行,排行榜实现
这个功能可以推算地理位置的信息,两地的距离
只有6个命令
//两极无法添加,我们一般会下载城市数据,直接通过java程序导入
127.0.0.1:6379> geoadd china:city 116.23128 40.22077 beijing //把城市的经纬度信息加入redis中
(integer) 1
127.0.0.1:6379> geoadd china:city 121.48941 31.40527 shanghai
(integer) 1
127.0.0.1:6379> geoadd china:city 106.54041 29.40268 chongqing
(integer) 1
127.0.0.1:6379> geoadd china:city 113.88308 22.55329 shenzheng
(integer) 1
127.0.0.1:6379> geoadd china:city 108.93425 34.23053 xian
(integer) 1
127.0.0.1:6379> geopos china:city beijing//获取城市的经纬度
1) 1) "116.23128265142440796"
2) "40.22076905438526495"
计算两地直线距离
后面可以加单位:默认是米,km 千米,mi 英里,ft英尺
127.0.0.1:6379> geodist china:city beijing xian
"927537.1497"
127.0.0.1:6379> geodist china:city beijing chongqing km
"1491.5364"
查询某位置半径内的元素
127.0.0.1:6379> georadius china:city 110 30 1000 km//输入在地点经纬度为(110,30),1000km内的元素.
1) "chongqing"
2) "xian"
3) "shenzheng"
127.0.0.1:6379> georadius china:city 110 30 1000 km withcoord//同时输出经纬度信息
1) 1) "chongqing"
2) 1) "106.54040783643722534"
2) "29.40268053517299762"
2) 1) "xian"
2) 1) "108.93425256013870239"
2) "34.23053097599082406"
3) 1) "shenzheng"
2) 1) "113.88307839632034302"
2) "22.55329111565713873"
127.0.0.1:6379> georadius china:city 110 30 1000 km count 2//只输入2个
1) "chongqing"
2) "xian"
查询一个元素附近的功能
127.0.0.1:6379> georadiusbymember china:city beijing 1000 km//查询距离北京1000km内的元素
1) "beijing"
2) "xian"
将经纬度转化为geohash字符串
127.0.0.1:6379> geohash china:city beijing chongqing
1) "wx4sucvncn0"
2) "wm5z22s7520"
什么是基数?
A{1,3,5,7,8,7}
B{1,3,5,7,8}
Redis2.8.9版本更新了Hyperloglog数据结构
Redis Hyperloglog基数统计算法
优点:占用的内存是固定,2^64不同的元素计数,只需要用12k内存
网页的UV(一个人访问一个网站多次,但是还是算作一个人)
传统的方式,set保存用户id,然后统计set中的元素数目作为标准判断
这个方式如果保存大量的用户id,就会比较麻烦,我们的目的是为了计数,而不是保存用户id
测试使用:
127.0.0.1:6379> pfadd mykey a b c d //创建第一组元素 mykey
(integer) 1
127.0.0.1:6379> pfadd mykey2 c d e f
(integer) 1
127.0.0.1:6379> pfcount mykey //统计mykey的基数数目
(integer) 4
127.0.0.1:6379> pfmerge mykey3 mykey mykey2 //合并两组mykey,mykey2生成mykey3
OK
127.0.0.1:6379> pfcount mykey3 //没有重复计算c,d
(integer) 6
如果允许容错,那么一定可以使用hyperloglog
如果不允许容错,就使用set或者自己的数据类型即可
位存储
统计用户信息,活跃,不活跃,登陆,未登录,打卡,365打卡,两个状态,都可以使用bitmaps
bitmaps位图,数据结构,都是二进制位来进行记录,就只有0和1两个状态
365天=365bit 1字节=8bit 46个字节左右
测试:
127.0.0.1:6379> setbit sign 0 1
(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 1
(integer) 0
127.0.0.1:6379> setbit sign 4 1
(integer) 0
127.0.0.1:6379> setbit sign 5 1
(integer) 0
127.0.0.1:6379> setbit sign 6 0
(integer) 0
查看指定天是否打卡
127.0.0.1:6379> getbit sign 6
(integer) 0
127.0.0.1:6379> getbit sign 0
(integer) 1
127.0.0.1:6379> getbit sign 3
(integer) 1
统计打卡天数
setbit key [start end] 统计key的第start~end字节有多少个值为1
这李的start一般从0开始,每个占8个数值,0就是[0,7] 1就是[8,15]
setbit key 0 3 :求[0,31]这个区间的范围1的个数
127.0.0.1:6379> setbit sign 0 1
(integer) 0
127.0.0.1:6379> setbit sign 5 1
(integer) 0
127.0.0.1:6379> setbit sign 11 1
(integer) 0
127.0.0.1:6379> setbit sign 15 1
(integer) 0
127.0.0.1:6379> setbit sign 19 1
(integer) 0
127.0.0.1:6379> bitcount sign
(integer) 5
127.0.0.1:6379> bitcount sign 10 20
(integer) 0
127.0.0.1:6379> bitcount sign 1 3
(integer) 3
127.0.0.1:6379> bitcount sign 0 1
(integer) 4
127.0.0.1:6379> bitcount sign 0 2
(integer) 5
127.0.0.1:6379> bitcount sign 1 2
(integer) 3
127.0.0.1:6379> bitcount sign 2 5
(integer) 1
视频学习链接:https://www.bilibili.com/video/BV1mc411h719?from=search&seid=16419983121936876555