redis默认是16个库,0号-15号,通过-n指定
redis启动客户端(命令行形式):
->redis-cli(默认连接到6379)
->redis-cli -h(可以看帮助)
->redis-cli -p 6380(连接6380)
->set k380:1 hello
->get k380:1(返回hello)
->select 8(选择8号库)
->get k380:1(无数据)
->exit(退出)
->redis-cli -p 6380 -n 8
->redis-cli
->help(告诉help的使用方式)
->help 点击Tab挨个选择或者补全
->help @generic(全局,基本配置,@表示分组,这组有keys/flushdb尽量不要使用等等)
->help @五种基本的类型(string,list,set,sorted_set,hash)
->help @string(把这个类型所有的命令展示出来)
string:字符串、数值和bitmap
->help set
->set k1 hello
->set k1 ooxx nx(nx表示k1不存在才设置,使用场景,分布式锁,一堆人拿着很多链接对一个单线程的redis发起set k1 nx,谁成功了,谁就拿到锁了)
->set k2 hello xx(xx表示,只有存在的时候才能操作成功。xx只能更新)
->mset k3 a k4 b
->mget k3 k4
->get k1 (hello)
->append k1 " world"
->get k1 (hello world)
->getrange k1 6 10/-1 (world)
->setrange k1 6 mashibing
->get k1 (hello mashibing)
正反向索引:正向012,反向-1 -2 -3
->strlen k1 (15)
->type k1 (string,key里面会有一个type,描述的是value的类型)
什么类型由命令的分组决定,命令比如set是@string的,那么这个key和value就是哪个类型的。
->set k1 99
->type k1 (string)
->object help
->object encoding k2 (embstr:emb编码的string)
->object encoding k1 (int,redis的5个类型中并没有int类型,并不是用type去看的int,但编码encoding有可能是string,有可能是int,因为redis有数值的操作)
->incr k1
->get k1 (100)
->incrby k1 22 (100+22)
->decr k1
->decrby k1 22
->incrbyfloat k1 0.5
以上对redis提供对数值的操作,可以用于抢购、秒杀、详情页、点赞、评论,为了规避并发下对数据库的事务操作,完全由redis内存操作代替。
二进制安全:redis自有的特征,在redis进程与外界交互的时候,传输的是字节流(按一个字符一个字节,字节数组,编码并没有影响数据的存储),不是字符流。
如果启动redis客户端不带着参数 --raw,redis只会显示ascii码,超过ascii码按照16进制显示,如果启动redis客户端带着--raw,会触发编码级别的格式化,当set一个汉字后,再get一个汉字,redis可以显示该汉字。
object encoding 作用相当于加速运算的过程,假如执行incr k1,如果object encoding k1是个int,那么可以直接运算;如果是个raw,可以尝试转成int进行加1;如果是embstr,直接报错。
外围客户端啥编码,redis不知道,给redis存的是先变成字节数组的内容。所以在redis外围的用户端如何编码和解码要先沟通好,redis里边是没有数据类型的。
->redis-cli --raw
->set k1 中
->get k1 (中)
->exit
->redis-cli
->keys * (k1)
->get k1 (\xe4\xb8\xad,encoding是utf-8编码下与redis通信,strlen为3,按字节个数算)
->set k1 hello
->getset k1 mashibing (设置新值并返回旧值)
msetnx/mgetnx,特别是msetnx能保证原子性操作,一个操作失败,所有的操作都失败。
@string分组里面,还有很多关于bit(位)的操作,位命令
->help setbit
->setbit k1 1 1 (把字节的1号位变成 1 )
->get k1 (@, 01000000, k1的长度为1)
->setbit k1 7 1
->get k1 (A, 01000001,k1的长度为1)
->setbit k1 9 1
->get k1 (A@,redis是以一个字节为显示的,k1的长度变为2, 01000001 01000000)
->help bitpos
->bitpos k1 1(要寻找的二进制位,0/1) 0(区间开始,这是字节的索引) 0(区间结束,这是字节的索引)
->1 (返回位的索引)
->bitpos k1 1 1 1
->9 (返回位的索引,全量的)
->bitpos k1 1 0 1
->1
->bitcount k1 0 1(计算1在字节区间出现的次数)
->3
->bitop operation(位的操作:与或非等) destkey(目标key) key[key ...](参与运算的key)
->setbit k1 1 1
->setbit k1 7 1
->get k1 ("A")
->setbit k2 1 1
->setbit k2 6 1
->get k1 ("B")
->bitop and andkey k1 k2
->get andkey ("@")
->bitop or orkey k1 k2
->get orkey ("C")
bitmap是很有用的东西,看下面两个需求,redis面试基本会问。
需求1:公司有用户系统(用户表),统计用户登录天数,且窗口随机(随机给定一个区间,去查询)。
算成本复杂度:假如现在用mysql数据库,常见做法是,登录表里面至少存以下字段:日期(4字节),用户id(4字节)。假如是京东,这张表的数据及其大,查询时老板给出一个随机窗口,遍历所有的数据,成本极其高,怎么优化?(redis解决)
redis解决:一年365或366天,大方一点算400天,用400个二进制位,400/8=50个字节,用50个字节可以最大记录一个用户全年的登录状态。
例如:
->setbit sean 1 1:sean这个人第二天登录了
->setbit sean 365 1:sean这个人第366天登录了
->strlen sean ("46" 顶多46个字节)
统计最后16天,sean这个人的登录次数
->bitcount sean -2 -1 ("1")
需求2:京东618做活动:送礼物,大库备货多少礼物,假设京东有2亿用户(活跃用户统计:随机窗口,连续登录要去重)
->setbit 20210101(key:为日期) 6 1(位图为用户id的映射,假如a使用的是第7个二进制位)
->setbit 20210102 5 1(20210102,b用户登录,b使用的是第6个二进制位)
->bitop or orkey 20210101 20210102
->bitcount orkey 0 -1