redis笔记
redis笔记
一、Redis的安装
1.下载安装包
1.1进入官网下载安装包
Redis官方网站 | Redis中文官方网站 |
---|---|
http://redis.io | http://redis.cn/ |
1.2.打开WinSCP将安装文件拖到服务器的安装目录之下。
2.下载安装
2.1、安装C语言的编译环境
yum install centos-release-scl scl-utils-build
yum install -y devtoolset-8-toolchain
scl enable devtoolset-8 bash
2.2、测试gcc版本
gcc --version
如果没有则使用命令:
yum install gcc
若之前放到服务器的文件是压缩包则进行解压缩操作
解压命令:tar -zxvf redis-6.2.1.tar.gz
解压缩之后进入目录
cd redis-6.2.1
2.3.进行编译安装
2.3.1、在redis目录下执行make操作
2.3.1.1、编译错误解决
2.3.1.1.1、emalloc/jemalloc.h.
(执行make命令只是为了编译好,执行之后可能遇到提示emalloc/jemalloc.h.这是因为没有准备好C语言的编译环境,解决办法输入)
make distclean
make MALLOC=libc
2.3.1.1.2、 release .h
解决方法:
步骤:1.cd 到文件中的src目录
2.chmod +x mkreleasehdr.sh
3.make distclean
4.make MALLOC=libc
2.4、编译完成之后进行安装
make install
到此安装过程结束。
2.5.重点(防止入侵)
找到配置文件然后设置密码(永久的)
安装redis后服务器被攻击了两次:redis有漏洞建议修改密码,端口号,启动时用非root用户。(此处忘记做笔记,遇事不决,客问百度)
二、启动
2.1、前台启动
redis-server;启动服务;
前台启动,若命令行窗口关闭则服务器停止,所以一般不推荐使用;
Ctrl+c:停止运行;
2.2、后台启动
2.2.1、将redis.conf备份
cp redis.conf /etc/redis.conf
可以备份到其他目录;
查看备份情况:
cd /etc
ll ,ls
2.2.2、修改后台启动设置(将daemonize no改为yes)
改的是备份的文件,etc下的文件
修改redis.conf文件将里面的daemonize no 改成 yes,让服务在后台启动。
cd /etc;
vi redis.conf;
/daemo;(关键字搜索);
然后完成修改
2.2.3、启动redis
cd /usr/local/bin;回到bin目录之下;
redis-server /etc/redis.conf; 启动,注意是备份的.conf文件;
后台启动在窗口关闭的情况下还可以运行是比较推荐的方法;
2.2.4、用客户端访问
redis-cli;
2.2.5、验证测试是否为正常的状态
auth "密码"#若设置了密码则要先进行密码验证,否则ping不通
ping;出现结果为pong
2.2.6、关闭redis
方法一:在bin目录下输入redis-cli shutdown;
方法二:直接在终端输入shutdown;
方法三:杀死进程;
三、redis中的5大数据类型
3.1、redis的key操作
set key value #设置值
get key #获取值
keys * #查看当前库所有key (匹配:keys *1)
exists key #判断某个key是否存在
type key #查看你的key是什么类型
del key #删除指定的key数据
unlink key #根据value选择非阻塞删除
#仅将keys从keyspace元数据中删除,真正的删除会在后续异步操作。
expire key 10 #10秒钟:为给定的key设置过期时间
ttl key #查看还有多少秒过期,-1表示永不过期,-2表示已过期
select #切换数据库
dbsize #查看当前数据库的key的数量
flushdb #清空当前库
flushall #通杀全部库
3.2、字符串String
3.2.1、常用指令
127.0.0.1:6379> set k1 v1
OK
127.0.0.1:6379> get k1
"v1"
127.0.0.1:6379> APPEND k1 app #拼接
(integer) 5
127.0.0.1:6379> get k1
"v1app"
127.0.0.1:6379> STRLEN k1#计算长度
(integer) 5
127.0.0.1:6379> EXISTS key #检查是否存在
(integer) 0
127.0.0.1:6379> EXISTS k1
(integer) 1
127.0.0.1:6379> TYPE k1#检查KEY的类型
string
127.0.0.1:6379>
#对值的增加和减少
127.0.0.1:6379> set view 0
OK
127.0.0.1:6379> INCR view #自增一
(integer) 1
127.0.0.1:6379> INCR view
(integer) 2
127.0.0.1:6379> get view
"2"
127.0.0.1:6379> DECR view #自减一
(integer) 1
127.0.0.1:6379> INCRBY view 10 #设置步长,设置增量
(integer) 11
127.0.0.1:6379> DECRBY view 10#设置步长,设置减量
(integer) 1
127.0.0.1:6379> get view
"1"
127.0.0.1:6379> FLUSHdb#清空当前库,跑路
OK
#对字符串的截取
127.0.0.1:6379> set key1 wshiyigedashuaibi
OK
127.0.0.1:6379> get key1
"wshiyigedashuaibi"
127.0.0.1:6379> GETRANGE key1 0 3 #截取[0,3]的字符串
"wshi"
127.0.0.1:6379> GETRANGE key1 0 -1
"wshiyigedashuaibi"
127.0.0.1:6379>
#替换字符串
127.0.0.1:6379> get key1
"wshiyigedashuaibi"
127.0.0.1:6379> SETRANGE key1 1 xx #第几个字符替换为什么
(integer) 17
127.0.0.1:6379> get key1
"wxxiyigedashuaibi"
127.0.0.1:6379>
#{setex key1 10 'yuangy'(设置过期时间)}
#{SETNX key2 'shixiaoyuanya'(是否存在设置,多用于分布式锁中)}
127.0.0.1:6379> setex key1 10 'yuangy'
OK
127.0.0.1:6379> get key1#10秒之内
"yuangy"
127.0.0.1:6379> get key1#10秒之后
(nil)
127.0.0.1:6379> ttl key3#查看还有多少秒过期,-1表示永不过期,-2表示已过期
(integer) -2
127.0.0.1:6379> SETNX key2 'shixiaoyuanya' #查看是否存在若不存在创建
(integer) 1
127.0.0.1:6379> keys *
1) "key2"
127.0.0.1:6379> SETNX key2 'shixiao'#查看是否存在若存在创建失败
(integer) 0
127.0.0.1:6379> get key2
"shixiaoyuanya"
127.0.0.1:6379>
#批量创建获取key,是原子性操作(mset,mget)
127.0.0.1:6379> mset k1 d1 k2 d2 k3 d3
OK
127.0.0.1:6379> mget k1 k2 k3
1) "d1"
2) "d2"
3) "d3"
#原子性体现(K1已经存在)
127.0.0.1:6379> msetnx k1 d1 k4 d4
(integer) 0
127.0.0.1:6379> get k4
(nil)
127.0.0.1:6379>
#进阶版掌握使用(对象)
#set student:1 {name xiaoyuan:,age:3} #student:1对象值为json字符来保存一个对象!
#mset 类:id:属性 属性值 类:id:属性 属性值
127.0.0.1:6379> mset student:1:name xiaoyuan student:1:age 20
OK
127.0.0.1:6379> mget student:1:name student:1:age
1) "xiaoyuan"
2) "20"
127.0.0.1:6379> mset student:2:name xiaozhang student:2:age 30
OK
127.0.0.1:6379> mget student:1:name student:1:age student:2:name student:2:age
1) "xiaoyuan"
2) "20"
3) "xiaozhang"
4) "30"
127.0.0.1:6379>
#组合命令先get再set
127.0.0.1:6379> GETSET key7 xiaoyuan
(nil)
127.0.0.1:6379> get key7
"xiaoyuan"
127.0.0.1:6379> GETSET key7 xiaochen
"xiaoyuan"
127.0.0.1:6379> get key7
"xiaochen"
3.2.2、String应用场景
String类型是二进制安全的。意味着Redis的string可以包含任何数据。比如jpg图片或者序列化的对象。
String类型是Redis最基本的数据类型,一个Redis中字符串value最多可以是512M
String类似的使用场景: value除了是我们的字符串还可以是我们的数字!
●计数器
●统计多单位的数量
●粉丝数
●对象缓存存储!|
3.3、LIST列表
3.3.1、常用指令
基本上所有的list命令都是用L,R开头的(区分左右)
#插入值(lpush,RPUSH)
127.0.0.1:6379> lpush list a# 将一个或多个值插入到头部
(integer) 1
127.0.0.1:6379> lpush list b c
(integer) 3
127.0.0.1:6379> LRANGE list 0 -1#查看list中的值
1) "c"
2) "b"
3) "a"
127.0.0.1:6379> RPUSH list d#从尾部插入值
(integer) 4
127.0.0.1:6379> LRANGE list 0 -1
1) "c"
2) "b"
3) "a"
4) "d"
#Lindex通过下标获取值,llen获取list长度
127.0.0.1:6379> Lindex list 0
"b"
127.0.0.1:6379> Lindex list 1
"a"
127.0.0.1:6379> llen list
(integer) 2
3.3.1.3、替换(lset)
#替换
#lset 列表 第几个元素 替换后的值(若不存在报错,若存在则更新)
#EXISTS list检查是否存在
127.0.0.1:6379> EXISTS list
(integer) 0
127.0.0.1:6379> LPUSH lst a
(integer) 1
127.0.0.1:6379> EXISTS lst
(integer) 1
127.0.0.1:6379> lset lst 0 abeigail
OK
127.0.0.1:6379> LRANGE lst 0 -1
1) "abeigail"
127.0.0.1:6379>
#指定地方插入
#LINSERT 列表 after|before 在那个值周围插入 插入什么值
127.0.0.1:6379> LINSERT list BEFORE c woshibeichajinglaide
(integer) 7
127.0.0.1:6379> LRANGE list 0 -1
1) "f"
2) "e"
3) "d"
4) "woshibeichajinglaide"
5) "c"
6) "b"
7) "a"
127.0.0.1:6379> LINSERT list after c woshibeichajinglaide
(integer) 8
127.0.0.1:6379> LRANGE list 0 -1
1) "f"
2) "e"
3) "d"
4) "woshibeichajinglaide"
5) "c"
6) "woshibeichajinglaide"
7) "b"
8) "a"
127.0.0.1:6379>
#移除值(LPOP,RPOP)
127.0.0.1:6379> LPOP list #移除最左边的元素
"c"
127.0.0.1:6379> LRANGE list 0 -1
1) "b"
2) "a"
3) "d"
127.0.0.1:6379> RPOP list#移除最右边的元素
"d"
127.0.0.1:6379> LRANGE list 0 -1
1) "b"
2) "a"
#移除指定的值(lrem)
#lrem 集合 几个 精确的value值
127.0.0.1:6379> LRANGE list 0 -1
1) "c"
2) "d"
3) "c"
4) "b"
5) "a"
127.0.0.1:6379> lrem list 1 a
(integer) 1
127.0.0.1:6379> LRANGE list 0 -1
1) "c"
2) "d"
3) "c"
4) "b"
127.0.0.1:6379> lrem list 2 c
(integer) 2
127.0.0.1:6379> LRANGE list 0 -1
1) "d"
2) "b"
127.0.0.1:6379>
#ltrim截取操作,改变了list的值只剩下裁剪后的值
127.0.0.1:6379> LRANGE list 0 -1
1) "e"
2) "d"
3) "c"
4) "a"
5) "b"
6) "a"
127.0.0.1:6379> ltrim list 1 2
OK
127.0.0.1:6379> LRANGE list 0 -1
1) "d"
2) "c"
127.0.0.1:6379>
#组合命令(rpoplpush)#移除列表的最后一一个 元素,将他移动到新的列表中!
127.0.0.1:6379> LRANGE list 0 -1
1) "a"
2) "d"
3) "c"
127.0.0.1:6379> RPOPLPUSH list mylist
"c"
127.0.0.1:6379> LRANGE list 0 -1
1) "a"
2) "d"
127.0.0.1:6379> LRANGE mylist 0 -1
1) "c"
127.0.0.1:6379>
3.3.2、LIST应用场景
●在redis里面,list其实就是一个链表
●我们可以把list视作, 栈、队列、阻塞队列!(从哪里加入和取值)
●生产者,消费者。
●取消关注
3.4.set集合
set值不能重复
3.4.1、常用指令
####################################################
127.0.0.1:6379> sadd set a
(integer) 1
127.0.0.1:6379> sadd set b c d#存值
(integer) 3
127.0.0.1:6379> SMEMBERS set#取值
1) "b"
2) "a"
3) "d"
4) "c"
####################################################
127.0.0.1:6379> SISMEMBER set f#查看值是否存在
(integer) 0
127.0.0.1:6379> SISMEMBER set a
(integer) 1
127.0.0.1:6379> SCARD set#查看集合有几个值
(integer) 4
127.0.0.1:6379>
####################################################
127.0.0.1:6379> SMEMBERS set
1) "d"
2) "c"
127.0.0.1:6379> srem set d c #移除元素
(integer) 2
127.0.0.1:6379> SMEMBERS set
(empty array)
127.0.0.1:6379>
####################################################
#随机抽取元素
127.0.0.1:6379> SMEMBERS set
1) "b"
2) "a"
3) "d"
4) "c"
127.0.0.1:6379> SRANDMEMBER set 3
1) "a"
2) "c"
3) "d"
127.0.0.1:6379> SRANDMEMBER set 2
1) "a"
2) "d"
127.0.0.1:6379>
####################################################
#删除随机的key
127.0.0.1:6379> SMEMBERS myset
1) "e"
2) "v"
3) "o"
4) "l"
5) "c"
127.0.0.1:6379> spop myset
"e"
127.0.0.1:6379> SMEMBERS myset
1) "v"
2) "o"
3) "l"
4) "c"
127.0.0.1:6379>
####################################################
#将一个指定的key移动到另外一个set集合中
127.0.0.1:6379> SMEMBERS myset
1) "v"
2) "o"
3) "l"
4) "c"
127.0.0.1:6379> sadd myset1 d
(integer) 1
127.0.0.1:6379> smove myset myset1 o
(integer) 1
127.0.0.1:6379> SMEMBERS myset1
1) "d"
2) "o"
127.0.0.1:6379>
####################################################
#数字集合类
127.0.0.1:6379> SMEMBERS myset
1) "v"
2) "l"
3) "c"
127.0.0.1:6379> SMEMBERS myset1
1) "d"
2) "o"
3) "c"
127.0.0.1:6379> sdiff myset myset1#差集
1) "v"
2) "l"
127.0.0.1:6379> SINTER myset myset1#并集
1) "c"
127.0.0.1:6379> SUNION myset myset1#交集
1) "c"
2) "l"
3) "v"
4) "o"
5) "d"
127.0.0.1:6379>
3.4.2、set应用场景
●数字集合类
:并集
:交集
:差集
●微博,A用户将所有关注的人放在- -个set集合中!将它的粉丝也放在-一个集合中 !
一些软件上的共同关注(并集)
推荐好友,共同爱好
3.5、hash(哈希)
3.2.1、常用指令
####################################################
127.0.0.1:6379> hset myhash k1 v1
(integer) 1
127.0.0.1:6379> hget myhash k1
"v1"
127.0.0.1:6379> hmset myhash k1 haha k2 hahaha
OK
127.0.0.1:6379> hmget myhash k1 k2
1) "haha"
2) "hahaha"
127.0.0.1:6379> hgetall myhash#查看所有
1) "k1"
2) "haha"
3) "k2"
4) "hahaha"
127.0.0.1:6379> hkeys myhash#查看key值
1) "k2"
2) "k1"
3) "k3"
4) "k4"
127.0.0.1:6379> hvals myhash#查看values值
1) "hahaha"
2) "haha"
3) "wshi"
4) "yuangy"
127.0.0.1:6379>
127.0.0.1:6379> hdel myhash k1#删除某个key
(integer) 1
127.0.0.1:6379> hgetall myhash
1) "k2"
2) "hahaha"
127.0.0.1:6379>
####################################################
#计算长度
127.0.0.1:6379> hgetall myhash
1) "k2"
2) "hahaha"
3) "k1"
4) "haha"
5) "k3"
6) "wshi"
7) "k4"
8) "yuangy"
127.0.0.1:6379> hlen myhash
(integer) 4
127.0.0.1:6379>
####################################################
#判断是否存在
127.0.0.1:6379> hexists myhash k1
(integer) 1
127.0.0.1:6379> hexists myhash k5
(integer) 0
127.0.0.1:6379>
####################################################
#HINCRBY计算(3+6—6-2)
127.0.0.1:6379> hmget myhash k1 k2
1) "haha"
2) "3"
127.0.0.1:6379> HINCRBY myhash k2 6
(integer) 9
127.0.0.1:6379> HINCRBY myhash k2 -6
(integer) 3
127.0.0.1:6379> HINCRBY myhash k2 -2
(integer) 1
127.0.0.1:6379>
####################################################
#检查是否存在然后添加(如果不存在就不添加)
127.0.0.1:6379> hset myhash k2 haha
(integer) 0
127.0.0.1:6379> hset myhash k3 xiaoyuan
(integer) 1
127.0.0.1:6379> hmget myhash k1 k2 k3
1) "haha"
2) "haha"
3) "xiaoyuan"
127.0.0.1:6379>
####################################################
3.5.2、应用场景
●Map集合,key-map!时候这个值是一个map集合!本质和String类型没有太大区别,还是一个简单的key-vlaue !
●hash变更的数据user name age,尤其是是用户信息之类的,经常变动的信息! hash 更适合于对象的存储, String更加适合字符串存储。
3.6、zset(有序集合)
3.6.1、常用指令
####################################################
127.0.0.1:6379> zadd myset 1 a
(integer) 1
127.0.0.1:6379> zadd myset 2 b 3 c
(integer) 2
127.0.0.1:6379> ZRANGE myset 0 -1
1) "a"
2) "b"
3) "c"
127.0.0.1:6379>
####################################################
#排序
127.0.0.1:6379> zadd chengji 99 zhangsan 88 lihua 100 wangwu
(integer) 3
127.0.0.1:6379> zadd chengji 76 xiaolei
(integer) 1
127.0.0.1:6379> ZRANGE chengji 0 -1 #小到大
1) "xiaolei"
2) "lihua"
3) "zhangsan"
4) "wangwu"
127.0.0.1:6379> ZRANGEBYSCORE chengji -inf +inf #小到大
1) "xiaolei"
2) "lihua"
3) "zhangsan"
4) "wangwu"
127.0.0.1:6379> ZRANGEBYSCORE chengji -inf +inf withscores #小到大并且带上排序条件
1) "xiaolei"
2) "76"
3) "lihua"
4) "88"
5) "zhangsan"
6) "99"
7) "wangwu"
8) "100"
127.0.0.1:6379> ZRANGEBYSCORE chengji -inf 80 withscores #小到多少排序
1) "xiaolei"
2) "76"
127.0.0.1:6379> ZREVRANGEBYSCORE chengji +inf -inf#大到小排序
1) "wangwu"
2) "zhangsan"
3) "lihua"
4) "xiaolei"
127.0.0.1:6379> zcount chengji 60 90# 获取指定区间的数量
(integer) 2
####################################################
#移除某个元素
127.0.0.1:6379> zrem chengji wangwu
(integer) 1
127.0.0.1:6379> ZREVRANGEBYSCORE chengji +inf -inf
1) "zhangsan"
2) "lihua"
3) "xiaolei"
3.6.2、应用场景
●Redis有序集合zset与普通集合set非常相似,是一个没有重复元素的字符串集合。
●在set的基础上,增加了一个值,set k1 v1
zset k1 score1 v1
这个评分(score)被用来按照从最低分到最高分的方式排序集合中的成员。集合的成员是唯一的,但是评分可以是重复了 。
●工资表,成绩表的存储,带权重的查询。
●普通消息,1,重要消息2 ,带权重进行判断!
●排行榜应用实现,取Top N测试!
四、三种普通类型
4.1、geospatial地理位置
4.1.1、常用指令
####################################################
#geoadd添加城市的经纬度(一般在java程序中一键导入,此处指令为方便学习)(无法定位两极的经纬度)(经度,纬度,城市名称)
127.0.0.1:6379> geoadd china:clty 109.479 30.295 enshi
(integer) 1
127.0.0.1:6379> geoadd china:clty 109.722 30.602 jianshi
(integer) 1
127.0.0.1:6379> geoadd china:clty 114.298 30.584 wuhan
(integer) 1
127.0.0.1:6379> geoadd china:clty 103.823 36.058 lanzhou
(integer) 1
127.0.0.1:6379> geoadd china:clty 110.340 31.042 badong
(integer) 1
127.0.0.1:6379>
####################################################
#获取指定城市的经纬度
127.0.0.1:6379> GEOPOS china:clty enshi
1) 1) "109.47899848222732544"
2) "30.2950012373855202"
127.0.0.1:6379> GEOPOS china:clty enshi badong
1) 1) "109.47899848222732544"
2) "30.2950012373855202"
2) 1) "110.33999830484390259"
2) "31.0419987713696699"
127.0.0.1:6379>
####################################################
#测算直线距离
#m表示单位为米。
#km表示单位为干米。
#mi表示单位为英里。
#ft 表示单位为英尺。
127.0.0.1:6379> GEODIST china:clty jianshi wuhan#单位m
"438099.1347"
127.0.0.1:6379> GEODIST china:clty jianshi wuhan km#单位Km
"438.0991"
127.0.0.1:6379>
####################################################
#通过某一个用户的经纬度来测算附近多少千米内的用户
127.0.0.1:6379> GEORADIUS china:clty 110 30 100 km
#测算经纬度110 30为中心100km的城市
1) "jianshi"
2) "enshi"
127.0.0.1:6379> GEORADIUS china:clty 110 30 100 km withdist
#测算经纬度为110 30内100km的城市并显示距离
1) 1) "jianshi"
2) "72.0839"
2) 1) "enshi"
2) "59.8972"
127.0.0.1:6379> GEORADIUS china:clty 110 30 100 km withcoord
#测算经纬度为110 30内100km的城市并显示经纬度
1) 1) "jianshi"
2) 1) "109.72200125455856323"
2) "30.6019990600411731"
2) 1) "enshi"
2) 1) "109.47899848222732544"
2) "30.2950012373855202"
127.0.0.1:6379> GEORADIUS china:clty 110 30 100 km withdist count 1
#测算经纬度为110 30内100km的城市并显示距离。但只查询一个
1) 1) "enshi"
2) "59.8972"
127.0.0.1:6379>
####################################################
#找出指定元素距离内的元素
127.0.0.1:6379> GEORADIUSBYMEMBER china:clty enshi 100 km
1) "enshi"
2) "jianshi"
127.0.0.1:6379> GEORADIUSBYMEMBER china:clty enshi 1000 km
1) "enshi"
2) "jianshi"
3) "badong"
4) "lanzhou"
5) "wuhan"
127.0.0.1:6379>
####################################################
#geohash命令将返回11个字符的Geohash字符串!(基本上不会用上)
#将二维的经纬度转换为一维的字符串,如果两个字符串越接近,那么则距离越近!
127.0.0.1:6379> geohash china:clty enshi jianshi
1) "wmmu7701jt0"
2) "wmqn0fcjef0"
127.0.0.1:6379>
4.1.2、应用场景
●朋友的定位,附近的人,打车距离计算?
●Redis的Geo在Redis3.2版本就推出了!
●可以查询一-些测试数据: http://www.jsons.cn/lngcodeinfo/0706D99C19A781A3/
●这个功能可以推算地理位置的信息,两地之间的距离,方圆几里的人! .
●有效的经度从-180度到180度。
●有效的纬度从-85.05112878度到85.05112878度。
●GEO底层的实现原理其实就是Zset !我们可以使用Zset命令来操作geo !
4.2、Hyperloglog(基数)
4.2.1、常用指令
127.0.0.1:6379> PFADD key q w e r t y u i o p #创建第一组数据
(integer) 1
127.0.0.1:6379> PFCOUNT key#统计个数
(integer) 10
127.0.0.1:6379> PFADD key1 q w e z x c v b n#创建第二组数据
(integer) 1
127.0.0.1:6379> PFCOUNT key1
(integer) 9
127.0.0.1:6379> PFMERGE key2 key key1#合并,合并的过程中去重了
OK
127.0.0.1:6379> PFCOUNT key2
(integer) 16
4.2.2、应用场景
●基数:不重复的元素。Hyperloglog统计技术是专业的。
●优点:占用的内存是固定, 2^64不同的元素的技术,只需要废12KB内存!
●网页的UV (一个人访问一个网站多次.但是还是算作一个人! )
●传统的方式,set 保存用户的id ,然后就可以统计set中的元素数量作为标准判断!
这个方式如果保存大量的用户id ,就会比较麻烦!我们的目的是为了计数,而不是保存用户id ;
4.3、Bitmaps(位存储)
127.0.0.1:6379> setbit qiandao 1 0
(integer) 0
127.0.0.1:6379> setbit qiandao 2 1
(integer) 0
127.0.0.1:6379> setbit qiandao 3 1
(integer) 0
127.0.0.1:6379> setbit qiandao 4 0
(integer) 0
127.0.0.1:6379> setbit qiandao 5 1#第几天签到,如果签到则为1
(integer) 0
127.0.0.1:6379> getbit qiandao 3#查看第三天是否签到
(integer) 1
127.0.0.1:6379> getbit qiandao 1#查看第一天是否签到
(integer) 0
127.0.0.1:6379> bitcount qiandao#统计签到天数
(integer) 3
4.3.2、应用场景
●统计用户信息,活跃,不活跃!登录、未登录!
●打卡, 365打卡!。redis只作为缓存。后面打卡签到数据肯定是要持久化到数据库的。用redis只是为了不频繁修改数据库, 实际上数据库打卡这些还是要存的,只不过通过redis持久化就可以了
●Bitmaps位图,数据结构!都是操作二进制位来进行记录,就只有0和1两个状态!
五.事务
5.1、事务基本命令和锁
正常执行事务
127.0.0.1:6379> multi#开启事务
OK
#命令入队
127.0.0.1:6379(TX)> set k1 v1
QUEUED
127.0.0.1:6379(TX)> set k2 k3
QUEUED
127.0.0.1:6379(TX)> get k2
QUEUED
127.0.0.1:6379(TX)> set k3 v3
QUEUED
127.0.0.1:6379(TX)> exec#执行事务
1) OK
2) OK
3) "k3"
4) OK
放弃事务
127.0.0.1:6379> multi
OK
127.0.0.1:6379(TX)> set k1 v1
QUEUED
127.0.0.1:6379(TX)> set k2 k3
QUEUED
127.0.0.1:6379(TX)> get k1
QUEUED
127.0.0.1:6379(TX)> set k3 v3
QUEUED
127.0.0.1:6379(TX)> DISCARD#取消事务
OK
127.0.0.1:6379> get k1
(nil)
127.0.0.1:6379> get k2
(nil)
127.0.0.1:6379>
编译型异常(代码有错误,命令输入错误),事务中的所有命令都不会执行
127.0.0.1:6379> multi
OK
127.0.0.1:6379(TX)> set k1 v1
QUEUED
127.0.0.1:6379(TX)> set k2# 代码输入错误
(error) ERR wrong number of arguments for 'set' command
127.0.0.1:6379(TX)> set k3 v3
QUEUED
127.0.0.1:6379(TX)> exec#执行,事务中的所有命令都不会执行
(error) EXECABORT Transaction discarded because of previous errors.
127.0.0.1:6379> get k1#事务中的所有命令都不会执行
(nil)
127.0.0.1:6379>
运行时异常( 1/0) ,如果事务队列中存在语法性,那么执行命令的时候,其他命令是可以正常执行的,错误命令抛出异常!
127.0.0.1:6379> multi
OK
127.0.0.1:6379(TX)> set k1 v1
QUEUED
127.0.0.1:6379(TX)> INCR k1#对字符串进行加一属于语法错误
QUEUED
127.0.0.1:6379(TX)> set k2 v2
QUEUED
127.0.0.1:6379(TX)> get k2
QUEUED
127.0.0.1:6379(TX)> get k1
QUEUED
127.0.0.1:6379(TX)> exec#其他指令运行,语法错误的指令不运行
1) OK
2) (error) ERR value is not an integer or out of range
3) OK
4) "v2"
5) "v1"
127.0.0.1:6379>
监控 Watch
●悲观锁
无论什么时候都需要加锁,认为什么时候都会出现问题。
●乐观锁
很乐观,认为什么时候都不会出问题,所以不会上锁!更新数据的时候去判断一下,在此期间是否有人修改过这个数据!
获取version
更新的时候比较version
正常执行
127.0.0.1:6379> set money 100
OK
127.0.0.1:6379> set out 0
OK
127.0.0.1:6379> WATCH money
OK
127.0.0.1:6379> MULTI
OK
127.0.0.1:6379(TX)> DECRby money 20
QUEUED
127.0.0.1:6379(TX)> INCRby out 20
QUEUED
127.0.0.1:6379(TX)> exec
1) (integer) 80
2) (integer) 20
测试多线程修改值,使用watch可以当做redis的乐观锁操作!
127.0.0.1:6379> WATCH money#对钱进行监控
OK
127.0.0.1:6379> MULTI
OK
127.0.0.1:6379(TX)> DECRby money 10
QUEUED
127.0.0.1:6379(TX)> INCRby out 10
QUEUED
127.0.0.1:6379(TX)> exec#执行之前,另外一个线程,修改了我们的值,这个时候,就会导致事务执行失败
(nil)
如果修改失败,则先解锁然后重新加锁
127.0.0.1:6379> unwatch#先解锁
OK
127.0.0.1:6379> WATCH money#重新监视这个事务
OK
127.0.0.1:6379> MULTI
OK
127.0.0.1:6379(TX)> INCRby out 80
QUEUED
127.0.0.1:6379(TX)> DECRby money 80
QUEUED
127.0.0.1:6379(TX)> exec
1) (integer) 180
2) (integer) 820
127.0.0.1:6379>
5.2、基本概念
●在关系型数据库中,事务要么同时成功,要么同时失败(原子性)。
●redis事务没有隔离性级别的概念
所有的命令在事务中,并没有直接被执行!只有发起执行命令的时候才会执行! Exec
●在redis单条命令是保存原子性的,但是事务不保证原子性。
●Redis事务本质:一组命令的集合! 一个事务中的所有命令都会被序列化,在事务执行过程的中,会按照顺序执行!
一次性,顺序性,排他性。
●Redis事务是一个单独的隔离操作:事务中的所有命令都会序列化、按顺序地执行。事务在执行的过程中,不会被其他客户端发送来的命令请求所打断。
●Redis事务的主要作用就是串联多个命令防止别的命令插队。
●redis的事务:
1.开启事务(multi)
2.命令入队(其他命令)
3.执行事务(exec)
六.Jedis
6.1、导入依赖
<!--导入jedis的包-->
<dependency>
<groupId>redis.clients</groupId>
<artifactId>jedis</artifactId>
<version>3.2.0</version>
</dependency>
<dependency>
<!-- fastjson-->
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>1.2.79</version>
</dependency>
6.2、创建远程连接
1.在服务器上创建安全组(开放6379端口号此处不做演示)
2.关闭只有本地连接的设置
3.关闭保护模式
4.修改密码(最好修改)
在这里设置的密码是一次性的在杀死进程之后就无了。
永久的密码需要在配置文件中修改。
5.利用java代码进行连接
public static void main(String[] args) {
// 1.new jedis对象
Jedis jedis=new Jedis("域名",6379);
//运行打印出pong则连接成功
System.out.println(jedis.ping());
}
6.3、测试相关命令
验证指令全部来源于第三章和第四章下面只做展示
6.3.1、key
//设置值
jedis.set("k1", "v1");
jedis.set("k2", "v2");
jedis.set("k3", "v3");
Set<String> keys = jedis.keys("*");
System.out.println(keys.size());
// 查看有多少key
for (String key : keys) {
// 循环遍历key
System.out.println(key);
}
//查看是否存在
System.out.println(jedis.exists("k1"));
//检查是否过期
System.out.println(jedis.ttl("k1"));
// 获取key的value值
System.out.println(jedis.get("k1"));
设置值之后可以用命令验证
127.0.0.1:6379> get k1
"v1"
127.0.0.1:6379> get k2
"v2"
127.0.0.1:6379> get k3#这三个值都是利用java代码生成
"v3"
127.0.0.1:6379>
6.3.2、String
//String加和减举例
jedis.mset("k1","3","k2","5");
System.out.println("加法运算前"+jedis.mget("k1","k2"));
jedis.incrBy("k2", 4);
System.out.println("加法运算后"+jedis.mget("k1","k2"));
//运行结果
加法运算前[3, 5]
加法运算后[3, 9]
6.3.3、list
//list指定地方插入展示
jedis.lpush("list","a","b","c");
//获取list中的值:方法1
System.out.println(jedis.lrange("list",0,-1));
//获取list中的值:方法2
List<String> list = jedis.lrange("list",0,-1);
for (String element : list) {
System.out.println(element);
}
jedis.linsert("list", ListPosition.BEFORE,"b","charudezhi");
System.out.println(jedis.lrange("list",0,-1));
结果展示
方法1:[c, b, a]
方法2:c
方法2:b
方法2:a
[c, charudezhi, b, a]
6.3.4、set
//set举列子
jedis.sadd("myset","a","b","c","d");
System.out.println(jedis.smembers("myset"));
//移除元素
jedis.srem("myset","b");
System.out.println(jedis.smembers("myset"));
结果展示:
PONG
[b, c, d, a]
[c, d, a]
6.3.5、hash
//hash展示
jedis.hset("myhash","k1","v1");
System.out.println(jedis.hget("myhash","k1"));
Map<String,String> map = new HashMap<String,String>();
map.put("k2","v2");
map.put("k3","v3");
jedis.hmset("myhash1",map);
List<String> result = jedis.hmget("myhash1", "k2","k3");
for (String element : result) {
System.out.println(element);
}
结果展示
PONG
v1
v2
v3
七.整合springoot
7.1.导入依赖
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-pool2</artifactId>
<version>2.6.0</version>
</dependency>
7.2.配置项
#Redis服务器地址
spring.redis.host=域名
#Redis服务器连接端口
spring.redis.port=端口号默认6379
#Redis数据库索引(默认为0)
spring.redis.database= 0
#连接超时时间(毫秒)
spring.redis.timeout=1800000
#连接池最大连接数(使用负值表示没有限制)
spring.redis.lettuce.pool.max-active=20
#最大阻塞等待时间(负数表示没限制)
spring.redis.lettuce.pool.max-wait=-1
#连接池中的最大空闲连接
spring.redis.lettuce.pool.max-idle=5
#连接池中的最小空闲连接
spring.redis.lettuce.pool.min-idle=0
7.3.配置类模板(直接用)
@EnableCaching
@Configuration
public class RedisConfig extends CachingConfigurerSupport {
@Bean
public RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory factory) {
RedisTemplate<String, Object> template = new RedisTemplate<>();
RedisSerializer<String> redisSerializer = new StringRedisSerializer();
Jackson2JsonRedisSerializer jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer(Object.class);
ObjectMapper om = new ObjectMapper();
om.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
om.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL);
jackson2JsonRedisSerializer.setObjectMapper(om);
template.setConnectionFactory(factory);
//key序列化方式
template.setKeySerializer(redisSerializer);
//value序列化
template.setValueSerializer(jackson2JsonRedisSerializer);
//value hashmap序列化
template.setHashValueSerializer(jackson2JsonRedisSerializer);
return template;
}
@Bean
public CacheManager cacheManager(RedisConnectionFactory factory) {
RedisSerializer<String> redisSerializer = new StringRedisSerializer();
Jackson2JsonRedisSerializer jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer(Object.class);
//解决查询缓存转换异常的问题
ObjectMapper om = new ObjectMapper();
om.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
om.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL);
jackson2JsonRedisSerializer.setObjectMapper(om);
// 配置序列化(解决乱码的问题),过期时间600秒
RedisCacheConfiguration config = RedisCacheConfiguration.defaultCacheConfig()
.entryTtl(Duration.ofSeconds(600))
.serializeKeysWith(RedisSerializationContext.SerializationPair.fromSerializer(redisSerializer))
.serializeValuesWith(RedisSerializationContext.SerializationPair.fromSerializer(jackson2JsonRedisSerializer))
.disableCachingNullValues();
RedisCacheManager cacheManager = RedisCacheManager.builder(factory)
.cacheDefaults(config)
.build();
return cacheManager;
}
}
7.4、test测试
@RestController
@RequestMapping("/redisTest")
public class RedisTestController {
@Autowired
private RedisTemplate redisTemplate;
//引入我们自己写的配置类模版文件
@GetMapping
public String testRedis() {
//设置值到redis
redisTemplate.opsForValue().set("k1","value1");
//从redis获取值
String name = (String)redisTemplate.opsForValue().get("key1");
return name;
}
}
8.redis.conf配置文件
8.1.配置文件unit单位对大小写不敏感!
8.2.include
类似jsp中的include,多实例的情况可以把公用的配置文件提取出来。
8.3.网络
8.4.通用的GENERAL
8.5.SNAPSHOTTING 快照
持久化,在规定的时间内,执行了多少次操作,则会持久化到文件.rdb. aof。
redis是内存数据库,如果没有持久化,那么数据断电及失!瑞迪斯是内存数据库,如果没有持久化,那么数据断电及失!
#如果900s内,如果至少有一个1 key进行了修改,我们及进行持久化操作
save 900 1
#如果300s内,如果至少10 key进行了修改,我们及进行持久化操作
save 300 10
#如果60s内,如果至少10000 key进行了修改,我们及进行持久化操作
save 60 1000
8.6.安全(SECURITY )
永久设置,需要再配置文件中进行设置。
在命令中设置密码,只是临时的。重启redis服务器,密码就还原了。
8.7.limit限制
8.8MEMORY MANAGEMENT
maxmemory <bytes>
# redis 配置最大的内存容量
maxmemory-policy noeviction # 内存到达上限之后的处理策略
1、volatile-1ru:#只对设置了过期时间的key进行LRU (默认值)
2、a11keys-1ru #删除1ru算法的key
3、volatile-random#随机删除即将过期key
4、allkeys-random#随机删除
5、volatile-tt1 #删除即将过 期的
6、noeviction #永不过期,返回错误
8.9APPEND ONLY MODE
9.持久化操作
Redis是内存数据库,如果不将内存中的数据库状态保存到磁盘,那么一-旦服务器进程退出 ,服务器中的数据库状态也会消失。所以Redis提供了持久化功能!学习之前好好学习conf配置文件。
9.1、RDB(Redis DataBase)
在指定的时间间隔内将内存中的数据集快照写入磁盘。
Redis会单独创建(fork)一个子进程来进行持久化,会先将数据写入到 一个临时文件中,待持久化过程都结束了,再用这个临时文件替换上次持久化好的文件。 整个过程中,主进程是不进行任何IO操作的,这就确保了极高的性能 如果需要进行大规模数据的恢复,且对于数据恢复的完整性不是非常敏感,那RDB方式要比AOF方式更加的高效。的缺点是最后一次持久化后的数据可能丢失。
官方的默认配置差不多够用,一般不需要去配置文件更改。
触发机制:
1、save的规则满足的情况下,会自动触发rdb规则
2、执行flushall命令,也会触发我们的rdb规则!
3、退出redis,也会产生rdb文件!
备份就自动生成一个dump.rdb文件
如何恢复
1.只需要将rdb文件放在我们redis启动目录就可以, redis启动的时候会自动检查dump.rdb恢复其中的数据!
2、查看需要存在的位置
127.0.0.1:6379> config get dir
1) "dir”
2) "/usr/1ocal/bin" # 如果在这个目录下存在dump.rdb 文件,启动就会自动恢复其中的数据
优缺点
#优点
适合大规模的数据恢复
对数据完整性和一致性要求不高更适合使用
节省磁盘空间
恢复速度快
#缺点
Fork的时候,内存中的数据被克隆了一份,大致2倍的膨胀性需要考虑
虽然Redis在fork时使用了写时拷贝技术,但是如果数据庞大时还是比较消耗性能。
在备份周期在一定间隔时间做一次备份,所以如果Redis意外down掉的话,就会丢失最后一次快照后的所有修改。
9.2、AOF(Append Only File)
以日志的形式来记录每个写操作(增量保存),将Redis执行过的所有写指令记录下来(读操作不记录), 只许追加文件但不可以改写文件,redis启动之初会读取该文件重新构建数据,换言之,redis 重启的话就根据日志文件的内容将写指令从前到后执行一次以完成数据的恢复工作
10.可视化工具安装
Redis桌面管理器(又名RDM)是一个快速、简单、支持跨平台的 Redis 桌面管理工具,适用于Mac OS X,Windows和Linux的GUI应用程序。
下载,安装(傻瓜式安装):
下载链接(版本一直在更新最好换一个):https://github.com/uglide/RedisDesktopManager
一直下一步。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 震惊!C++程序真的从main开始吗?99%的程序员都答错了
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理
· 单元测试从入门到精通
· 上周热点回顾(3.3-3.9)
· winform 绘制太阳,地球,月球 运作规律