Java - 中间件 - Redis
一、Linux系统下安装Redis
官方下载地址
这里使用6.2.4版本的
https://download.redis.io/releases/redis-6.2.4.tar.gz
wget https://download.redis.io/releases/redis-6.2.4.tar.gz
#获取资源
tar -zxvf redis-6.2.4.tar.gz
#解压资源
cd redis-6.2.4/
#进入redis目录下
make MALLO=libc
#因为这是源码文件,通过make MALLO=libc进行编译
...
#一通操作之后,redis建议你先运行一下make test,测试是否有问题
make test
# 运行完之后,出现两个错误
yum install tcl-devel
#根据错误,先安装tcl
make test
#再次测试
...
mkdir redis
#创建一个单独属于redis的安装目录
#进入redis安装包解压的目录下,执行以下代码
make install PREFIX=/data/redis
#将安装路径放到redis文件夹中
cd /data/redis/
#去redis文件夹下发现里面只有一个bin文件见
cp ../redis-6.2.4/redis.conf redis.conf
#将配置文件拷贝过来
cd /data/redis/bin/
#进入bin目录
./redis-server ../redis.conf
#启动文件,把配置文件加载进来
ok,到此为止,redis安装完成,不过此时你会发现有很多问题,如下
- 端口无法访问
firewall-cmd --permanent --zone=public --add-port=6379/tcp
firewall-cmd --reload
firewall-cmd --zone=public --query-port=6379/tcp
- 只能127.0.0.1(本机)访问
修改配置文件中的bind 127.0.0.1 为0.0.0.0
打开配置文件,通过查找bind ,修改内容
- 启动之后出现指定页面,没办法关闭
打开配置文件,修改 daemonize no为yes
- 输入的中午出现乱码
./redis-cli --raw
用这种方式打开redis就可以了
二、常见类型
2.1 String
在String中可以储存三种数据类型,分别是:String字符串、Int整数、Float浮点数
- 常见操作
- get key
获取对应key的值,如果没有则返回 nil- set key value [EX seconds|PX milliseconds] [NX|XX]
设置键值对,没有键的时候创建,有的时候就覆盖 加ex代表过了几秒这个键值对就删除 加px代表多了多少毫秒就删除,加nx代表存在key的时候修改失败,避免修改已存在数据 xx只有存在key才会修改成功- del key
删除键值对- mset key value [key value…]
批量设置键值对- mget key [key…]
批量返回,在程序中执行时,会以一个list返回- strlen key
获取value的长度,一个汉字占3个长度- append key value
向key后面追加value的内容- getrange key start end
获取指定的长度 ,getrange key 0 -1 返回所有长度 ,下标从0开始 ,从start(包含)到end(包含)结束- incr key
当存储的数据是整型时,对数据进行递增1- incrby key value
指定递增的大小 incrby key 100,一次递增100- decr key
当存储的数据是整型时,对数据进行递减1- decrby key value
指定递减的大小 decrby key 100,一次递减100- incrbyfloat key value
当数据时浮点数时,指定递增的大小 incrbyfloat key 9.1,一次递增9.1,decrbyfloat不存在- setbit key index [0|1]
rdedis中的数据是按8位二进制的形式存储的。set bit可以修改对应位置的二进制值
修改key中,第index个位置的值为[0或者1]- getbit key index
获取key的第index的位置上的二进制值- bitpos key vlaue(0|1)
查询key对应的值的第一个0或者1的位置- bitcount key
查询这个key对应的值中存在多少个二进制值1
set a: b :c value
创建多级目录,可以用来保存对象,但是会消耗大量内存,因为保存的key也很多
- 应用场合
- 用作缓存(以读操作为主的数据)
- 分布式session
- 通过set nx(唯一限制) 和 ex(过期)实现分布式锁
- incr全局ID
- incr 全局计数器
- incr 限流
- 位操作
2.2 Hash
hash内部可以存在多个键值对,但是hash的value只能存储字符串,不可以多重嵌套
- 与String的区别
- 相对String来说,节约了内存空间,因为多个键值对放在了一起
- 减少了key冲突的可能
- 如果需要批量获取的时候,操作简化,也可以减少cpu消耗
- String 可以设置过期时间,hash不可以对内部的键值对设置过期时间,只可以对外层键值对进行过期设置
- hash不支持bit操作,无法通过bit运算
- 一个hash里面,如果内容太多,会导致redis单个节点容量过大
- 常见操作
- hset key field value [field value …]
设置hash内容,一个key可以包含多个field和value,主要适用于对象- hmset key field value [field value …]
作用同上,可以设置多个hash值- hget key field
获取一个hash里面的指定field的值- hmget key field [field …]
获取一个hash里面的一个或多个指定field的值- hincrby key field value
针对整型数据,指定key的field的值,增加 value大小,使用负进行递减- hincrbyfloat key field value
针对浮点数数据,指定key的field的值,增加 value大小,使用负进行递减- hexists key field
判断某一个field是否剖存在,返回 1 代表存在- hdel key
删除key,仅限于hash- hdel key field [field …]
删除key中的field,仅限于hash- hlen key
返回hash的元素个数
- 应用场景
- 储存复杂对象
- 购物车(案例)
2.3 List
- 常用操作
- lpush key element [element …]
在左边增加一个或多个元素- rpush key element [element …]
在右边增加一个或多个元素- lpop key [count]
从左边开始取出元素,count是取几个,不写就默认取一个- rpop key [count]
从右边开始取出元素,count是取几个,不写就默认取一个- lindex key index
通过下标获取到对应位置的元素,从0开始,不是取出- lrange key start stop
通过下标范围进行获取数据, 如果stop是-1 ,代表全部获取,不是取出
- 应用场景
- 实现消息队列
- 内容时间线(动态、朋友圈)
2.4 Set
存储一个无序的String内容
- 常用操作
- sadd key member [member …]
向集合中增加元素,内容不可重复,增加进去之后并不会按照输入顺序进行排序- smembers key
查询集合中的所有元素,查询结果是无序的- scard key
查询集合长度- srandmember key [count]
随机返回指定长度的元素个数,不加count默认为1- spop key [count]
返回一个(或多个)随机元素,并从集合中删除- srem key member [member …]
从集合中删除指定的元素,可以一次删除多个- sismember key member
判断一个元素是不是集合中的数据,返回0代表不是,返回1代表是的- sdiff key [key …]
只在第一个集合中,不在第二个集合中,不加指定集合就只展示前者集合的数据- sinter key [key …]
在第一个和指定集合中都存在的数据,不加指定集合就只展示前者集合的数据- sunion key [key …]
在集合与指定集合之间合并去重,不加指定集合就只展示前者集合的数据
- 应用场景
- 使用set进行抽奖,spop
- 维护一组数据,比如用户点赞
- 商品标签
- 商品筛选
- 用户关注
通过集合之间的操作,计算关注情况,比如互相关注、关注的人是否关注了他人、可能认识的人等
2.5 ZSet
每一个元素都有一个分值,通过分值排序,如果分值相同,通过key的ASCII进行排序,越小的数据排列越靠前
- 常用操作
- zadd key score member [score member …]
向ZSet中添加数据,例如:zadd myzset 10 a 20 b 30 c 40 d 50 e,注意分值在前面- zrange key min max [WITHSCORES]
根据下标取出对应元素的内容 ,max为-1,代表全部取出,加上WITHSCORES,则输出分值- zrevrange key start stop [WITHSCORES]
反转取出的内容,分值越大越靠前- zrangebyscore key min max [WITHSCORES]
根据分值进行输出- zrem key member [member …]
删除元素中的内容- zcard key
获取ZSet的数据量- zincrby key increment member
将指定元素的分值增加 increment
-zrank key member
获取指定元素的下标- zscore key member
获取元素分值
- 应用场景
- 排行榜
2.6 Geo Spatial(地理位置)
- 常用操作
- geoadd key longitude latitude member [longitude latitude member …]
保存经纬度位置 例如 :geoadd citys 121.48 31.22 sh- geopos key member [member …]
获取一个或多个位置的经纬度- geodist key member1 member2 [m|km|ft|mi]
获取两个位置之间的距离,默认单位是m- georadius key longitude latitude radius m|km|ft|mi
找出在指定范围一定距离内的值,例如:georadius citys 113.01 28.19 5 km- georadiusbymember key member radius m|km|ft|mi
根据city查询一定范围内的值
三、Redis高级功能
3.1 发布订阅
- 订阅频道,一次可以订阅多个频道
subscribe channel [channel …]- 发布内容,向指定频道发布内容
publish channel message- 取消订阅频道,取消订阅的时候,不可以在已经订阅的界面内取消,因为这个时候已经阻塞了
unsubscribe [channel [channel …]]- 订阅指定内容的模块
psubscribe pattern [pattern …]
例如:psubscribe sports,订阅以sports结尾的频道
例如:psubscribe news,订阅以news开头的频道
例如:psubscribe news-weather,订阅news-weather频道
3.2 事务
- 语法
开启事务:multi
执行事务:exec
取消事务:discard
乐观锁:watch(乐观锁在事务开启之前就需要加上,如果锁定的值发生变化,则事务执行失败)
- 异常处理
- 在执行之前出现的问题:
这个时候出现的问题会直接报错,事务无法执行- 在执行之后出现的问题:
这个时候正确语句会被执行,错误语句无法执行,不支持原子性原则
- 特点
- 按事务顺序执行
- 不会受到其他客户端的干扰
- 不支持数据回滚
3.3 执行lua脚本
- 特点
优点
- 批量执行redis命令,减少网络开销
- redis中会将lua的命令视为整体的,可以变相的实现事务的原子性
- 通过lua脚本,实现lua脚本的复用
基本用法
eval script numkeys key [key ...] arg [arg ...] # eval 执行命令的起始符 # script 需要执行的命令,可以是文件,也可以是一行命令 # numbers 需要的参数的数量,不需要参数的话,设置为0 # KEYS[1],ARGV[1] 参数显示,lua脚本中,下标是从1开始的
使用实例
eval "return 'hello world'" 0 #输出 hello world eval "redis.call('set',KEYS[1],ARGV[1])" 1 qs 2673 #执行了redis的String的设置值的语句 可以通过get查询到内容
-
执行lua脚本
./redis-cli --eval qs.lua 0 # ./redis-cli --eval 文件名 参数数量
-
示例
对某一个ip地址进行限流,即在x秒内只能访问y次
-- lua脚本 local num = redis.call('incr',KEYS[1]) --对传过来的用户标识进行递增,如果不存在,则创建一个 1 if tonumber(num) ==1 then --如果是第一次访问 redis.call('expire',KEYS[1],ARGV[1]) --给传过来的用户标识创建过期时间 return 1 elseif tonumber(num)>tonumber(ARGV[2]) then --如果访问次数大于设置的次数 return 0 else return 1 end
-
将脚本添加到脚本缓存中,避免每次都加载文件
SCRIPT LOAD script ## 此时会返回一个sha值,eval sha值的时候,也是可以使用lua脚本的
-
查看指定的脚本是否已经被保存到缓存中
SCRIPT EXISTS script [script ...]
-
杀死所有执行中的脚本(脚本超时)
SCRIPT KILL
-
从脚本缓存中去掉所有的脚本
SCRIPT FLUSH