Redis基础学习

83 阅读12分钟

Redis

Redis 是一个开源(BSD许可)的,内存中的数据结构存储系统,它可以用作数据库、缓存和消息中间件。 它支持多种类型的数据结构,如 字符串(strings)散列(hashes)列表(lists)集合(sets)有序集合(sorted sets) 与范围查询, bitmapshyperloglogs地理空间(geospatial) 索引半径查询。 Redis 内置了 复制(replication)LUA脚本(Lua scripting)LRU驱动事件(LRU eviction)事务(transactions) 和不同级别的 磁盘持久化(persistence), 并通过 Redis哨兵(Sentinel)和自动 分区(Cluster)提供高可用性(high availability)。

安装

1、下载压缩包
wget http://download.redis.io/releases/redis-6.0.6.tar.gz
2、解压
tar xzf redis-6.0.6.tar.gz
3.进入redis目录
cd redis-6.0.6
4.查看gcc版本
gcc -v

如果没有gcc环境

1.下载安装gcc环境
yum install gcc-c++
2.升级gcc
yum -y install centos-release-scl 
yum -y install devtoolset-9-gcc devtoolset-9-gcc-c++ devtoolset-9-binutils
scl enable devtoolset-9 bash
长期使用gcc版本
echo "source /opt/rh/devtoolset-9/enable" >>/etc/profile  

确认gcc环境没有问题

编译:
make
检查是否成功:
make install
修改配置文件:
daemonize yes

性能测试

redis-benchmark -h localhost -p 6379 -c 100 -n 100000

基础知识

redis默认16个数据库

切换服务器数据库:

select 0

清除当前数据库:

flushdb

清除所有数据库:

flushall

五大数据类型

Redis-Key

检查key值存不存在

exists key

移除key

move key 1

设置过期时间

expire key seconds

查看过期时间

ttl key

查看所有的key

keys *

查看key的类型

type key

String

设置值

set key value

获取值

get key

拼接值

append key value

获取值得长度

strlen key

原子操作加1

incr key

原子操作减1

decr key

设置步长,制定增量

incrby key number

设置步长,制定减量

decrby key number

获取截取字符串

getrange key start end

指定位置替换字符串

setrange key start

设值和过期时间

setex key seconds value

设置key的值,如果有值设置失败返回0,如果没值设置成功返回1

setnx key value

同时设置多个值

mset k1 v1 k2 v2 k3 v3

同时获取多个key的值

mget k1 k2 k3

同时设置多个key的值,如果有一个key的值已存在设置不成功返回

msetnx k1 v1 k2 v2

先获取值后设置值

getset key value

String 类型的使用场景

1.计数器

2.统计多单位的数量

3.对象缓存存储

4.粉丝数

List

栈,队列,阻塞队列

从左边插入一个值:lpush
​
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    #从左边开始打印值
1"three"
2"two"
3"one"
#############################
从右边插入一个值: rpush
​
127.0.0.1:6379> rpush list one
(integer) 1
127.0.0.1:6379> rpush list two
(integer) 2
127.0.0.1:6379> rpush list three   #从右边插入一个值 
(integer) 3
############################### 
移除左边或右边的值: lpop rpop
​
127.0.0.1:6379> lpop list          #从左边移除一个值
"one"
127.0.0.1:6379> rpop list          #从右边移除一个值
"three"
#################################
获得特定位置的值: lindex
​
127.0.0.1:6379> lindex list 1      #获得指定位置的值
"two"
#################################
获得列表长度:llen
​
127.0.0.1:6379> llen list          #获得list的长度
(integer) 3
################################
移除指定的元素:lrem
​
127.0.0.1:6379> lrem list 2 one    #移除指定的元素
(integer) 2
#############################
截取:ltrim
​
127.0.0.1:6379> ltrim list 1 2   #截取对应长度的list
OK
127.0.0.1:6379> lrange list 0 1
1"two"
2"three"
###################################
移除列表最右边的元素加到另一个列表的左边: rpoplpush
​
127.0.0.1:6379> rpoplpush list mlist #移除列表最右边元素添加到另一个列表的左边
"three"
##################################
将列表中指定位置的元素替换为另一个值:lset
​
127.0.0.1:6379> lset list 1 two1     #将列表中指定位置的元素替换为另一个值,如果不存在会报错
OK
127.0.0.1:6379> lrange list 0 -1     
1"one"
2"two1"
3"three"
######################################
将某个具体的value插入到列表中某个元素的前面或后面 linsert
​
127.0.0.1:6379> linsert mlist before three four   #将元素添加到列表指定的元素之前
(integer) 4
127.0.0.1:6379> lrange mlist 0 -1
1"four"
2"three"
3"hello"
4"word"
127.0.0.1:6379> linsert mlist after hello new     #将元素添加到列表指定的元素之后
(integer) 5
127.0.0.1:6379> lrange mlist 0 -1
1"four"
2"three"
3"hello"
4"new"
5"word"
###########################################
阻塞操作:BRPOPBLPOP   #可以设置当获取数据时数据不存在的阻塞时间,当时限内获取到了数据则立即弹出元素
127.0.0.1:6379> brpop mlist 100
^[[A^H^H#获取不到数据进入阻塞
r^H #
r^H#
lpush list 1        #
1"mlist"#获取到了数据,立即将其弹出
2"one"
(86.40s)
127.0.0.1:6379> lrange mlist 0 -1
(empty array)

列表实际上是一个链表

Set

set中的值不能重复

sadd key value

set中添加一个元素

127.0.0.1:6379> sadd set hello#往set里添加一个元素
(integer1
127.0.0.1:6379> sadd set word
(integer1
127.0.0.1:6379> sadd set new
(integer1

smembers key

查看set中的元素

127.0.0.1:6379> smembers set        #查看set里的元素
1"new"
2"word"
3"hello"

srem key value

移除set中的指定元素

127.0.0.1:6379> srem set new           #移除set中的指定元素
(integer) 1
127.0.0.1:6379> smembers set
1"word"
2"hello"

srandmember set count

随机获取一个或多个set中的元素

127.0.0.1:6379> srandmember set 2   #随机获取两个set中的元素
1"fore"
2"new"

spop key

随机删除一个set集合中的元素

127.0.0.1:6379> spop set        #随机删除一个set集合中的元素
"fore"

smove key1 key2 value

将key1的value移动到key2中

127.0.0.1:6379> smove set set2 one    #将key1的value移动到key2中
(integer) 1
127.0.0.1:6379> smembers set2    
1"gouerzi"
2"one"

sdiff sinter sunion

差集:sdiff 交集:sinter 合集:sunion

127.0.0.1:6379> sdiff set set2        #差集
1"five"
2"six"
3"two"
4"new"
5"hello"
6"three"
7"word"
127.0.0.1:6379> sinter set set2   #交集
1"one"
127.0.0.1:6379> sunion set set2   #合集
1"two"
2"new"
3"five"
4"hello"
5"three"
6"word"
7"one"
8"six"
9"gouerzi"

Hash

hash中的值由键值对组成 key-field-vale

往key里面添加(获取)一个键值对

hset key field value
hget key field
127.0.0.1:6379> hset hash field1 yuanlei  #往hash里添加一个键值对
(integer) 1
127.0.0.1:6379> hget hash field1       #获取一个key中的键值对
"yuanlei"

往key里添加(获取)多个键值对

hmset key field1 value1 field2 value2
hmget key field1 field2
hgetall key
127.0.0.1:6379> hmset hash gouerzi linyuanhang var 1      #添加多个键值对
OK
127.0.0.1:6379> hmget hash gouerzi var                    #获取多个键值对
1"linyuanhang"
2"1"
127.0.0.1:6379> hgetall hash  #获取所有的键值对
1"field1"
2"yuanlei"
3"gouerzi"
4"linyuanhang"
5"var"
6"1"

获取key的长度

hlen

127.0.0.1:6379> hlen hash                    #获取hash的长度
(integer) 3
​

判断key中的指定字段是否存在

hexists key field

127.0.0.1:6379> hexists hash gouerzi#判断hash中的gouerzi是否存在
(integer) 1
​

获得所有的field(value)

hkeys key
127.0.0.1:6379> hkeys hash#获得所有的field
1"field1"
2"gouerzi"
3"var"
hkeys value
127.0.0.1:6379> hvals hash#获得所有的value
1"yuanlei"
2"linyuanhang"
3"1"

使field对应的value增加count个值

hincrby key field count

127.0.0.1:6379> hincrby hash var 2     #使hash中的var对应的值增加2
(integer) 3
127.0.0.1:6379> hvals hash
1"yuanlei"
2"linyuanhang"
3"3"

如果key中field不存在设置一个field返回1,存在的话设置失败返回0

hsetnx key field value

127.0.0.1:6379> hsetnx hash var 3#hash中的field里存在var 设值失败
(integer) 0
​

使用环境

hash更适合于对象的存储 比如用户信息 、商品信息等。

Zset

在set的基础上增加了一个值score利用score排序

设置key增加一个值

zadd key score value

127.0.0.1:6379> zadd zset 1998 zhangsan            #给zset增加了一个score为1998的值
(integer) 1
127.0.0.1:6379> zadd zset 1999 lisi 2001 wangwu    #同时设置两个值
(integer) 2

升序排序

zrangebyscore key min max
zrange key start end
127.0.0.1:6379> ZRANGEBYSCORE zset -inf +inf		#从负无穷大到正无穷大从小到大排序
1) "yuanlei"
2) "linyuanhang"
127.0.0.1:6379> zrange zset 0 -1
1) "yuanlei"
2) "zhangsan"
3) "lisi"
4) "linyuanhang"
5) "wangwu"

降序排序

zrevrange zset 0 -1

127.0.0.1:6379> zrevrange zset 0 -1                 #将zset降序排序
1) "wangwu"
2) "linyuanhang"
3) "lisi"
4) "zhangsan"
5) "yuanlei"

三种特殊数据类型

geospatial

添加一个经度纬度和名称

geoadd key longitude latituder member

127.0.0.1:6379> geoadd china:city 116.40 39.90 beijing     #添加北京的经度纬度
(integer) 1
127.0.0.1:6379> geoadd china:city 121.49 31.40 shanghai
(integer) 1

获得一个key中一个位置的经度和纬度

geopos key member

127.0.0.1:6379> geopos china:city beijing   #获得北京的经度和纬度
1) 1) "116.39999896287918091"
   2) "39.90000009167092543"

获得两个位置之间的距离

geodist key member1 member2 {m|km|ft|mi}

127.0.0.1:6379> geodist china:city beijing shanghai km   #获得北京和上海之间的距离
"1050.9182"

获得半径为radius圆圈内的所有member

georadius key longitude latitude radius

127.0.0.1:6379> georadius china:city 110 30 2000 km    #获得110 30附近半径为2000km圆圈内的其他member
1) "shanghai"
2) "beijing"

geohash key member

获得一个11个字符的geohash字符串

127.0.0.1:6379> geohash china:city shanghai beijing    #获得北京和上海的geohash
1) "wtw6ss4q600"
2) "wx4fbxxfke0"

geospatial的底层是基于zset实现,可以用zset的命令操作geospatial的key

Hyperloglog

基数统计的算法

基数:不重复的数

127.0.0.1:6379> pfadd hp a b c d e f f    #设置一个key为hp的值为a,b,c,d,e,f,f
(integer) 1
127.0.0.1:6379> pfcount hp                #获得key为hp的基数的个数
(integer) 6
127.0.0.1:6379> pfadd hp2 a b c g h i j k   #设置一个key为hp2的值为a,b,c,g,h,i,j,k
(integer) 1 
127.0.0.1:6379> pfmerge hp3 hp hp2         #将hp和hp2合并为hp3
OK
127.0.0.1:6379> pfcount hp3                #获得key为hp3中基数的个数
(integer) 11

使用场景:

一个人访问网站多次,还算做一个人

如果允许容错, 可以使用hyperloglog

Bitmaps

位存储

统计用户信息。活跃信息,打卡信息。两个状态的信息都可以用Bitmaps

设置key中某个位置的值

setbit key 0 1

127.0.0.1:6379> setbit bit 0 1                #设置bit中0位为1
(integer) 0
127.0.0.1:6379> setbit bit 1 1
(integer) 0
127.0.0.1:6379> setbit bit 1 0
(integer) 1
127.0.0.1:6379> setbit bit 3 0
(integer) 0
127.0.0.1:6379> setbit bit 2 1
(integer) 0

获得key中某位置的值

getbit key 0

127.0.0.1:6379> getbit bit 0           #获得bit中0位的值
(integer) 1
127.0.0.1:6379> getbit bit 1
(integer) 0
127.0.0.1:6379> getbit bit 2
(integer) 1
127.0.0.1:6379> getbit bit 3
(integer) 0

统计key中值为1的个数

bitcount key

127.0.0.1:6379> bitcount bit
(integer) 2

事务

开启事务:multi

提交事务:exec

退出事务:discard

127.0.0.1:6379> multi               #开启事务
OK
127.0.0.1:6379> set k1 v1
QUEUED
127.0.0.1:6379> discard				#退出事务
OK
127.0.0.1:6379> multi				#开启事务
OK
127.0.0.1:6379> set k1 v2
QUEUED
127.0.0.1:6379> exec				#提交事务
1) OK

编译型异常(代码语法有问题,事务中所有命令都不执行)

127.0.0.1:6379> multi
OK
127.0.0.1:6379> set k1 v1
QUEUED
127.0.0.1:6379> set k2 v2
QUEUED
127.0.0.1:6379> set k3					#语法有问题报错
(error) ERR wrong number of arguments for 'set' command
127.0.0.1:6379> set k4 v4
QUEUED
127.0.0.1:6379> exec					
(error) EXECABORT Transaction discarded because of previous errors.
127.0.0.1:6379> get k2					#其他命令未执行
(nil)

运行时异常(如果语法正确,命令存在逻辑性问题,错误命令抛出异常,正确命令可以正常执行)

127.0.0.1:6379> multi
OK
127.0.0.1:6379> set k1 v1				
QUEUED
127.0.0.1:6379> incr k1						#逻辑性有问题没有报错
QUEUED
127.0.0.1:6379> get k1
QUEUED
127.0.0.1:6379> exec
1) OK
2) (error) ERR value is not an integer or out of range   #抛出异常其他命令正常执行
3) "v1"

悲观锁:

正如其名比较悲观,具有强烈的独占和排他特性,整个数据处理的过程都加锁,性能不高

乐观锁:

正如其名比较乐观,认为一般情况下数据不会起冲突,只有在数据提交的时候才会通过机制来验证处理。

127.0.0.1:6379> watch money				#监控money
OK
127.0.0.1:6379> multi					#开启事务
OK
127.0.0.1:6379> decrby money 10			#编写命令
QUEUED
127.0.0.1:6379> exec					#提交事务,发现money值被改变,修改失败
(nil)

SpringBoot整合

1.导入依赖

2.配置文件

3.检测连接

Redis.conf详解

网络

bind 127.0.0.1  #绑定IP地址
protected-mode yes    #保护模式
port 6379         #端口

通用GENERAL

daemonize no   #以守护进程启动,默认是no,需要自己启动

pidfile /var/run/redis_6379.pid  #如果以后台方式运行,就需要制定一个pid文件

# This can be one of:
# debug (a lot of information, useful for development/testing)
# verbose (many rarely useful info, but not a mess like the debug level)
# notice (moderately verbose, what you want in production probably)
# warning (only very important / critical messages are logged)
loglevel notice   #日志级别
logfile ""    #指定日志文件名
databases 16   #数据库数量
always-show-logo yes    #是否显示Logo

快照

持久化,在规定的时间内,执行了多少次操作,会持久化

redis是内存数据库,如果没有持久化,数据断电就会丢失

save 900 1       	#如果900s内,至少有1个key进行了修改,进行持久化操作
save 300 10			#如果300s内,至少有10个key进行了修改,进行持久化操作
save 60 10000		#60s内,至少有10000个key进行了修改,进行持久化操作

stop-writes-on-bgsave-error yes      #如果持久化出错是否继续工作

rdbcompression yes             #是否压缩RDB文件 需要消耗cpu资源

rdbchecksum yes 			#保存RDB文件的时候,对错误进行检查效验

dir ./ 						#RDB文件保存的目录

REPLICATION 主从复制

SECURITY 安全

redis默认没有密码

设置密码:

127.0.0.1:6379> config get requirepass        #获得密码,默认没有密码
1) "requirepass"
2) ""
127.0.0.1:6379> config set requirepass "980810"   #设置密码
OK
127.0.0.1:6379> config get requirepass			#重新启动redis需要登录
(error) NOAUTH Authentication required.
127.0.0.1:6379> set name yuanlei      
(error) NOAUTH Authentication required.
127.0.0.1:6379> auth 980810						#登录输入密码
OK
127.0.0.1:6379> set name yuanlei
OK

订阅发布

一个用户订阅一个频道。

127.0.0.1:6379> SUBSCRIBE yuanlei					#订阅一个频道
Reading messages... (press Ctrl-C to quit)        
1) "subscribe"
2) "yuanlei"
3) (integer) 

另一个用户往频道里发送消息

127.0.0.1:6379> PUBLISH yuanlei "hello"
(integer) 1
127.0.0.1:6379> publish yuanlei "word"
(integer) 1
127.0.0.1:6379> 

订阅的用户获得频道里的消息

1) "message"
2) "yuanlei"
3) "hello"
1) "message"
2) "yuanlei"
3) "word"

Redis集群搭建

创建多个Redis配置文件,

1.修改端口号

2.修改pidfile

3.修改logfile

4.修改RDB文件名

使用不同的配置文件启动Redis服务

redis-server ./redis-1/redis-1.conf       #后面的为redis配置文件的路径

主从复制

默认情况下Redis都是主机

配置文件中修改replication为从机

replication masterip masterport 

打开redis输入slave命令

slaveof masterip masterport

哨兵模式