加载中...

Redis


参考文档:https://hexo-blog-ssm.oss-cn-hangzhou.aliyuncs.com/images/%E6%95%B0%E6%8D%AE%E5%BA%93/2019-IDEA-Redis.pdf

简介

  • Remote Dictionary Server(远程字典服务器),是一个用C语言编写的、开源的、基于内存运行并支持持久化的、高性能的NoSQL数据库.也是当前热门的NoSQL数据库之一。

特点

  • 支持数据持久化

    • Redis支持数据的持久化,可以将内存中的数据保持在磁盘中,重启的时候可以再次加载进行使用。
  • 支持多种数据结构

    • Redis不仅仅支持简单的key-value类型的数据,同时还提供list,set,zset,hash等数据结构的存储。
  • 支持数据备份

    • Redis支持数据的备份,即master-slave模式的数据备份。

安装

linux上安装,这个以前已经安装好,此处不在赘述,如需安装参考文档(阿里云盘有)

启动

前台启动

在任何目录下执行: redis-server

后台启动

在任何目录下执行: redis-server &

常用启动

在任何目录下执行:启动redis服务时,指定配置文件:redis-server redis.conf &

Redis3.2.9

cd usr/java/redis-3.2.9/src/
# 启动
./redis-server ../redis.conf &
# 指定连接客户端 -p 指定端口号
./redis-cli -a 123456 -h 192.168.174.131
# 关闭
redis-cli -a 123456 -h 192.168.174.131 shutdown

默认连接的是本机本地的redis

基本知识

  • 测试redis性能
[root@localhost src] redis-benchmark -a 123456 -h 192.168.174.131
  • 查看redis服务是否正常运行
# 进入客户端
./redis-cli -a 123456 -h 192.168.174.131
ping

PONG

  • 查看redis服务器的统计信息
# 进入客户端
./redis-cli -a 123456 -h 192.168.174.131
info # 查看redis服务器的所有的统计信息
info [信息段]# 查看redis服务器的指定的统计信息,如 info Replication
  • 默认创建 16个数据库,指定使用数据库
select index # index:0-15
  • 查看当前数据库实例中key的数目
dbsize
  • 查看当前数据库实例中所有的key
keys *
  • 清空数据库实例
flushdb
  • 清空所有数据库实例
flushall
  • 查看redis中所有的配置信息
config get *
  • 查看redis中指定的配置信息
# 查看redis中占用的端口号
config get port # get 后跟参数

redis的5种数据结构

  • 字符串类型string

    • 字符串类型是Redis中最基本的数据结构,它能存储任何类型的数据,包括二进制数据,序列化后的数据,JSON化的对象甚至是一张图片。最大512M。

    • key value
      username 张三
  • 列表类型list

    • Redis列表是简单的字符串列表,按照插入顺序排序,元素可以重复。你可以添加一个元素到列表的头部(左边)或者尾部(右边),底层是个链表结构。

    • key value
      region 北京 上海 天津
  • 集合类型set

    • RedisSetstring类型的无序无重复集合。

    • key value
      framework spring
      mybatis
      springcloud
  • 哈希类型hash

    • Redis hash 是一个string类型的fieldvalue的映射表,hash特别适合用于存储对象。

    • key loginuser
      field value
      uname 张三
      times 6
      region 北京
  • 有序集合类型zset (sorted set)

    • Redis 有序集合zset和集合set一样也是string类型元素的集合,且不允许重复的成员。不同的是zset的每个元素都会关联一个分数(分数可以重复),redis通过分数来为集合中的成员进行从小到大的排序。

    • key value score
      salary 张三 3500
      李四 5000
      王五 6500

常用操作命令

redis中有关key的操作命令

keys
  • 语法:keys pattern

  • 作用:查找所有符合模式pattern的key. pattern可以使用通配符。

通配符:

  • *:表示0或多个字符,例如:keys * 查询所有的key。

  • ?:表示单个字符,例如:wo?d , 匹配 word , wood

  • [] :表示选择[]内的一个字符,例如wo[or]d, 匹配word, wood, 不匹配wold、woord

keys

exists
  • 语法:exists key [key…]

  • 判断key在数据库中是否存在

返回值:整数,存在key返回1,其他返回0。使用多个key,返回存在的key的数量。

exists

move
  • 语法:move key db

  • 作用:移动key到指定的数据库,移动的key在原库被删除。

返回值:移动成功返回1,失败返回0.

move

ttl
  • 语法:ttl key

  • 作用:查看key的剩余生存时间(ttl: time to live),以秒为单位。

返回值:

l -1 :没有设置key的生存时间, key永不过期。

l -2:key不存在

ttl

expire
  • 语法:expire key seconds

  • 作用:设置key的生存时间,超过时间,key自动删除。单位是秒。

返回值:设置成功返回数字 1,其他情况是 0 。

expire

type
  • 语法:type key

  • 作用:查看key所存储值的数据类型

返回值:字符串表示的数据类型

type

rename
  • 语法:rename key newkey
  • 作用:将key改为名newkey。当 key 和 newkey 相同,或者 key 不存在时,返回一个错误。

当 newkey 已经存在时, RENAME 命令将覆盖旧值。

rename

del
  • 语法:del key [key…]

  • 作用:删除存在的key,不存在的key忽略。

返回值:数字,删除的key的数量。

del

字符串类型(string)

字符串类型是Redis中最基本的数据类型,它能存储任何形式的字符串,包括二进制数据,序列化后的数据,JSON化的对象甚至是一张图片。

字符串类型的数据操作总的思想是通过key操作value,key是数据标识,value是我们感兴趣的业务数据。

set
  • 语法:set key value
  • 功能:将字符串值 value 设置到 key 中,如果key已存在,后放的值会把前放的值覆盖掉。

返回值:OK表示成功

set

get
  • 语法:get key

  • 功能:获取 key 中设置的字符串值

返回值:key存在,返回key对应的value;key不存在,返回nil

get

append
  • 语法:append key value

  • 功能:如果 key 存在,则将 value 追加到 key 原来旧值的末尾如果 key 不存在,则将key 设置值为 value

返回值:追加字符串之后的总长度(字符个数)

append

strlen
  • 语法:strlen key
  • 功能:返回 key 所储存的字符串值的长度

返回值:如果key存在,返回字符串值的长度;key不存在,返回0

strlen

incr
  • 语法:incr key
  • 功能:将 key 中储存的数字值加1,如果 key 不存在,则 key 的值先被初始化为 0 再执行incr操作。

返回值:返回加1后的key值

incr

decr
  • 语法:decr key

  • 功能:将 key 中储存的数字值减1,如果 key 不存在,则么 key 的值先被初始化为 0 再执行 decr 操作。

返回值:返回减1后的key值

decr

incrby
  • 语法:incrby key offset

  • 功能:将 key 所储存的值加上增量值,如果 key 不存在,则 key 的值先被初始化为 0 再执行 INCRBY 命令。

返回值:返回增量之后的key值。

incrby

decrby
  • 语法:decrby key offset

  • 功能:将 key 所储存的值减去减量值,如果 key 不存在,则 key 的值先被初始化为 0 再执行 DECRBY 命令。

返回值:返回减量之后的key值。

decrby

getrange
  • 语法:getrange key startIndex endIndex
  • 功能:获取 key 中字符串值从 startIndex 开始到 endIndex 结束的子字符串,包括startIndex和endIndex, 负数表示从字符串的末尾开始,-1 表示最后一个字符。

返回值:截取后的字符串

setrange

setrange
  • 语法:setrange key offsetIndex value
  • 功能:用value覆盖key的存储的值从offset开始。

返回值:修改后的字符串的长度。

getrange

setex
  • 语法:setex key seconds value

  • 功能:设置key的值,并将 key 的生存时间设为 seconds (以秒为单位) ,如果key已经存在,将覆盖旧值。

返回值:设置成功,返回OK。

setex

setnx
  • 语法:setnx key value

  • 功能:setnx 是 set if not exists 的简写,如果key不存在,则 set 值,存在则不设置值。

返回值:设置成功,返回1

setnx

mset
  • 语法:mset key value [key value…]

  • 功能:同时设置一个或多个 key-value 对

返回值:设置成功,返回OK。

mset

mget
  • 语法:mget key [key …]

  • 功能:获取所有(一个或多个)给定 key 的值

返回值:包含所有key的列表,如果key不存在,则返回nil。

msetnx
  • 语法:msetnx key value[key value…]

  • 功能:同时设置一个或多个 key-value 对,如果有一个key是存在的,则设置不成功。

返回值:设置成功,返回1设置失败,返回0

msetnx

列表(list)

Redis列表是简单的字符串列表,按照插入顺序排序,左边(头部)、右边(尾部)或者中间都可以添加元素。链表的操作无论是头或者尾效率都极高,但是如果对中间元素进行操作,那效率会大大降低了。

列表类型的数据操作总的思想是通过key和下标操作value,key是数据标识,下标是数据在列表中的位置,value是我们感兴趣的业务数据。

lpush
  • 语法:lpush key value [value…]

  • 功能:将一个或多个值 value 插入到列表 key 的最左边(表头),各个value值依次插入到表头位置。

返回值:插入之后的列表的长度。

lpush

rpush
  • 语法:rpush key value [value…]

  • 功能:将一个或多个值 value 插入到列表 key 的最右边(表尾),各个 value 值按依次插入到表尾。

返回值:插入之后的列表的长度。

rpush

lrange
  • 语法:lrange key startIndex endIndex

  • 功能:获取列表 key 中指定下标区间内的元素,下标从0开始,到列表长度-1;下标也可以是负数,表示列表从后往前取,-1表示倒数第一个元素,-2表示倒数第二个元素,以此类推;startIndex和endIndex超出范围不会报错。

返回值:获取到的元素列表。

lrange

rpop
  • 语法:rpop key

  • 功能:移除并返回列表key尾部第一个元素,即列表右侧的第一个元素。

返回值:列表右侧第一个元素的值;列表key不存在,返回nil。

rpop

lindex
  • 语法:lindex key index

  • 功能:获取列表 key 中下标为指定 index 的元素,列表元素不删除,只是查询。0 表示列表的第一个元素,1 表示列表的第二个元素;index也可以负数的下标, -1 表示列表的最后一个元素, -2 表示列表的倒数第二个元素,以此类推。

返回值:key存在时,返回指定元素的值;Key不存在时,返回nil。

lindex

llen
  • 语法:llen key

  • 功能:获取列表 key 的长度

返回值:数值,列表的长度;key不存在返回0

llen

lrem
  • 语法:lrem key count value

  • 功能:根据参数 count 的值,移除列表中与参数 value 相等的元素,

    • count >0 ,从列表的左侧向右开始移除;
    • count < 0 从列表的尾部开始移除;
    • count = 0移除表中所有与 value 相等的值。

返回值:数值,移除的元素个数

lrem

ltrim
  • 语法:ltrim key startIndex endIndex

  • 功能:截取key的指定下标区间的元素,并且赋值给key。下标从0开始,一直到列表长度-1;下标也可以是负数,表示列表从后往前取,-1表示倒数第一个元素,-2表示倒数第二个元素,以此类推;startIndex和endIndex超出范围不会报错。

返回值:执行成功返回ok

ltrim

lset
  • 语法:lset key index value

  • 功能:将列表 key 下标为 index 的元素的值设置为 value。

设置成功返回ok ; key不存在或者index超出范围返回错误信息。

lset

linsert
  • 语法:linsert key before/after pivot value

  • 功能:将值 value 插入到列表 key 当中位于值 pivot 之前或之后的位置。key不存在或者pivot不在列表中,不执行任何操作。

返回值:命令执行成功,返回新列表的长度。没有找到pivot返回 -1, key不存在返回0。

linsert

集合类型(set)

Redis的Set是string类型的无序不重复集合。

集合类型的数据操作总的思想是通过key确定集合,key是集合标识,元素没有下标,只有直接操作业务数据和数据的个数。

sadd
  • 语法:sadd key member [member…]

  • 功能:将一个或多个 member 元素加入到集合 key 当中,已经存在于集合的 member 元素将被忽略,不会再加入。

返回值:加入到集合的新元素的个数(不包括被忽略的元素)。

sadd

smembers
  • 语法:smembers key

  • 功能:获取集合 key 中的所有成员元素,不存在的key视为空集合。

返回值:返回指定集合的所有元素集合,不存在的key,返回空集合。

smembers

sismember
  • 语法:sismember key member

  • 功能:判断 member 元素是否是集合 key 的元素

返回值:member是集合成员返回1,其他返回 0 。

sismember

scard
  • 语法:scard key

  • 功能:获取集合里面的元素个数

返回值:数字,key的元素个数。其他情况返回 0 。

scard

srem
  • 语法:srem key member [member…]

  • 功能:移除集合中一个或多个元素,不存在的元素被忽略。

返回值:数字,成功移除的元素个数,不包括被忽略的元素。

srem

srandmember
  • 语法:srandmember key[count]

  • 功能:只提供key,随机返回集合中一个元素,元素不删除,依然在集合中;提供了count时,count 正数, 返回包含count个数元素的集合,集合元素各不重复。count是负数,返回一个count绝对值的长度的集合,集合中元素可能会重复多次。

返回值:一个元素或者多个元素的集合

srandmember

spop
  • 语法:spop key[count]

  • 功能:随机从集合中删除一个或count个元素。

返回值:被删除的元素,key不存在或空集合返回nil。

spop

smove
  • 语法:smove src dest member

  • 功能:将 member 元素从src集合移动到dest集合,member不存在,smove不执行操作,返回0,如果dest存在member,则仅从src中删除member。

返回值:成功返回 1 ,其他返回 0 。

smove

sdiff
  • 语法:sdiff key key [key…]

  • 功能:返回指定集合的差集,以第一个集合为准进行比较,即第一个集合中有但在其它任何集合中都没有的元素组成的集合。

返回值:返回第一个集合中有而后边集合中都没有的元素组成的集合,如果第一个集合中的元素在后边集合中都有则返回空集合。

sdiff

sinter
  • 语法:sinter key key [key…]

  • 功能:返回指定集合的交集,即指定的所有集合中都有的元素组成的集合。

返回值:交集元素组成的集合,如果没有则返回空集合。

sinter

sunion
  • 语法:sunion key key [key…]

  • 功能:返回指定集合的并集,即指定的所有集合元素组成的大集合,如果元素有重复,则保留一个。

返回值:返回所有集合元素组成的大集合,如果所有key都不存在,返回空集合。

sunion

哈希类型(hash)

Redis的hash 是一个string类型的key和value的映射表,这里的value是一系列的键值对,hash特别适合用于存储对象。

哈希类型的数据操作总的思想是通过key和field操作value,key是数据标识,field是域,value是我们感

兴趣的业务数据。

hset
  • 语法:hset key field value [field value …]

  • 功能:将键值对field-value设置到哈希列表key中,如果key不存在,则新建哈希列表,然后执行赋值,如果key下的field已经存在,则value值覆盖。

返回值:返回设置成功的键值对个数。

hset

hget
  • 语法:hget key field

  • 功能:获取哈希表 key 中给定域 field 的值。

返回值:field域的值,如果key不存在或者field不存在返回nil。

hget

hmset
  • 语法:hmget key field [field…]

  • 功能:获取哈希表 key 中一个或多个给定域的值

返回值:返回和field顺序对应的值,如果field不存在,返回nil。

hmset

hmget
  • 语法:hmget key field [field…]

  • 功能:获取哈希表 key 中一个或多个给定域的值

返回值:返回和field顺序对应的值,如果field不存在,返回nil。

hmget

hgetall
  • 语法:hgetall key

  • 功能:获取哈希表 key 中所有的域和值

返回值:以列表形式返回hash中域和域的值,key不存在,返回空hash.

hgetall

hdel
  • 语法:hdel key field [field…]

  • 功能:删除哈希表 key 中的一个或多个指定域field,不存在field直接忽略。

返回值:成功删除的field的数量。

hdel

hlen
  • 语法:hlen key

  • 功能:获取哈希表 key 中域field的个数

返回值:数值,field的个数。key不存在返回0.

hlen

hexists
  • 语法:hexists key field

  • 功能:查看哈希表 key 中,给定域 field 是否存在

返回值:如果field存在,返回1,其他返回0。

hexists

hkeys
  • 语法:hkeys key

  • 功能:查看哈希表 key 中的所有field域列表

返回值:包含所有field的列表,key不存在返回空列表

hkeys

hvals
  • 语法:hvals key

  • 功能:返回哈希表 中所有域的值列表

返回值:包含哈希表所有域值的列表,key不存在返回空列表。

hvals

hincrby
  • 语法:hincrby key field int

  • 功能:给哈希表key中的field域增加int

返回值:返回增加之后的field域的值

hincrby

hincrbyfloat
  • 语法:hincrbyfloat key field float

  • 功能:给哈希表key中的field域增加float

返回值:返回增加之后的field域的值

hincrbyfloat

hsetnx
  • 语法:hsetnx key field value

  • 功能:将哈希表 key 中的域 field 的值设置为 value ,当且仅当域 field 不存在的时候才设置,否则不设置。

返回值:设值成功返回1,其他返回0.

hsetnx

有序集合类型(Zset)

Redis 有序集合zset和集合set一样也是string类型元素的集合,且不允许重复的成员。

不同的是zset的每个元素都会关联一个分数(分数可以重复),redis通过分数来为集合中的成员进行从小到大的排序。

zadd
  • 语法:zadd key score member [score member…]

  • 功能:将一个或多个 member 元素及其 score 值加入到有序集合 key 中,如果member存在集合中,则覆盖原来的值;score可以是整数或浮点数.

返回值:数字,新添加的元素个数.

zadd

zrange
  • 语法:zrange key startIndex endIndex [WITHSCORES]

  • 功能:查询有序集合,指定区间的内的元素。集合成员按score值从小到大来排序;startIndex和endIndex都是从0开始表示第一个元素,1表示第二个元素,以此类推; startIndex和endIndex都可以取负数,表示从后往前取,-1表示倒数第一个元素;WITHSCORES选项让score和value一同返回。

返回值:指定区间的成员组成的集合。

zrange

zrangebyscore
  • 语法:zrangebyscore key min max [WITHSCORES ] [LIMIT offset count]

  • 功能:获取有序集 key 中,所有 score 值介于 min 和 max 之间(包括min和max)的成员,有序成员是按递增(从小到大)排序;使用符号”(“ 表示包括min但不包括max;withscores 显示score和 value;limit用来限制返回结果的数量和区间,在结果集中从第offset个开始,取count个。

返回值:指定区间的集合数据

zrangebyscore

zrangebyscore

zrem
  • 语法:zrem key member [member…]

  • 功能:删除有序集合 key 中的一个或多个成员,不存在的成员被忽略。

返回值:被成功删除的成员数量,不包括被忽略的成员。

zrem

zcard
  • 语法:zcard key

  • 作用:获取有序集 key 的元素成员的个数。

返回值:key存在,返回集合元素的个数; key不存在,返回0。

zcard

zcount
  • 语法:zcount key min max

  • 功能:返回有序集 key 中, score 值在 min 和 max 之间(包括 score 值等于 min 或 max )的成员的数量。

返回值:指定有序集合中分数在指定区间内的元素数量。

zcount

zrank
  • 语法:zrank key member

  • 功能:获取有序集 key 中成员 member 的排名,有序集成员按 score 值从小到大顺序排列,从0开始排名,score最小的是0 。

返回值:指定元素在有序集合中的排名;如果指定元素不存在,返回nil。

zrank

zscore
  • 语法:zscore key member

  • 功能:获取有序集合key中元素member的分数。

返回值:返回指定有序集合元素的分数。

zscore

zrevrank
  • 语法:zrevrank key member

  • 功能:获取有序集 key 中成员 member 的排名,有序集成员按 score 值从大到小顺序排列,从0开始排名,score最大的是0 。

返回值:指定元素在有序集合中的排名;如果指定元素不存在,返回nil。

zrevrank

zrevrange
  • 语法:zrevrange key startIndex endIndex [WITHSCORES]

  • 功能:查询有序集合,指定区间的内的元素。集合成员按score值从大到小来排序;startIndex和endIndex都是从0开始表示第一个元素,1表示第二个元素,以此类推; startIndex和endIndex都可以取负数,表示从后往前取,-1表示倒数第一个元素;WITHSCORES选项让score和value一同返回。

返回值:指定区间的成员组成的集合。

zrevrange

zrevrangebyscore
  • 语法:zrevrangebyscore key max min [WITHSCORES ] [LIMIT offset count]

  • 功能:获取有序集 key 中,所有 score 值介于 max 和 min 之间(包括max和min)的成员,有序成员是按递减(从大到小)排序;使用符号”(“ 表示不包括min和max;withscores 显示score和 value;limit用来限制返回结果的数量和区间,在结果集中从第offset个开始,取count个。

返回值:指定区间的集合数据

zrevrangebyscore

新数据类型

Bitmaps

  • Bitmaps本身不是一种数据类型, 实际上它就是字符串(key-value) , 但是它可以对字符串的位进行操作。

  • Bitmaps单独提供了一套命令, 所以在Redis中使用Bitmaps和使用字符串的方法不太相同。 可以把Bitmaps想象成一个以位为单位的数组, 数组的每个单元只能存储0和1, 数组的下标在Bitmaps中叫做偏移量。

setbit
  • 格式:setbit设置Bitmaps中某个偏移量的值(0或1)*offset:偏移量从0开始

setbit

很多应用的用户id以一个指定数字(例如10000) 开头, 直接将用户id和Bitmaps的偏移量对应势必会造成一定的浪费, 通常的做法是每次做setbit操作时将用户id减去这个指定数字。

在第一次初始化Bitmaps时, 假如偏移量非常大, 那么整个初始化过程执行会比较慢, 可能会造成Redis的阻塞。

getbit
  • 格式:getbit获取Bitmaps中某个偏移量的值

获取键的第offset位的值(从0开始算)

返回值有的返回1,没有的返回0

getbit

bitcount

统计字符串被设置为1的bit数。一般情况下,给定的整个字符串都会被进行计数,通过指定额外的 start 或 end 参数,可以让计数只在特定的位上进行。start 和 end 参数的设置,都可以使用负数值:比如 -1 表示最后一个位,而 -2 表示倒数第二个位,start、end 是指bit组的字节的下标数,二者皆包含。

  • 格式:bitcount[start end] 统计字符串从start字节到end字节比特值为1的数量

返回key的数量

在这里插入图片描述

注意:redis的setbit设置或清除的是bit位置,而bitcount计算的是byte位置。

bitop
  • 格式:bitop and(or/not/xor) [key…]
  • bitop是一个复合操作, 它可以做多个Bitmaps的and(交集) 、 or(并集) 、 not(非) 、 xor(异或) 操作并将结果保存在destkey中。

bitop

常用于统计活跃用户数量

HyperLogLog

Redis HyperLogLog 是用来做基数统计的算法,HyperLogLog 的优点是,在输入元素的数量或者体积非常非常大时,计算基数所需的空间总是固定的、并且是很小的。

在 Redis 里面,每个 HyperLogLog 键只需要花费 12 KB 内存,就可以计算接近 2^64 个不同元素的基数。这和计算基数时,元素越多耗费内存就越多的集合形成鲜明对比。

但是,因为 HyperLogLog 只会根据输入元素来计算基数,而不会储存输入元素本身,所以 HyperLogLog 不能像集合那样,返回输入的各个元素。

什么是基数?

比如数据集 {1, 3, 5, 7, 5, 7, 8}, 那么这个数据集的基数集为 {1, 3, 5 ,7, 8}, 基数(不重复元素)为5。 基数估计就是在误差可接受的范围内,快速计算基数。

pfadd

格式:pfadd < element> [element …] 添加指定元素到 HyperLogLog 中

将所有元素添加到指定HyperLogLog数据结构中。如果执行命令后HLL估计的近似基数发生变化,则返回1,否则返回0。

pfadd

pfcount
  • 格式:pfcount [key …] 计算HLL的近似基数,可以计算多个HLL,比如用HLL存储每天的UV,计算一周的UV可以使用7天的UV合并计算即可

返回key的数量

pfcount

pfmerge
  • 格式:pfmerge [sourcekey …] 将一个或多个HLL合并后的结果存储在另一个HLL中,比如每月活跃用户可以使用每天的活跃用户来合并计算可得

在这里插入图片描述

Geospatial

Redis 3.2 中增加了对GEO类型的支持。GEO,Geographic,地理信息的缩写。该类型,就是元素的2维坐标,在地图上就是经纬度。redis基于该类型,提供了经纬度设置,查询,范围查询,距离查询,经纬度Hash等常见操作。

geoadd
  • 格式:geoadd< longitude> [longitude latitude member…] 添加地理位置(经度,纬度,名称)

geoadd

  • 两极无法直接添加,一般会下载城市数据,直接通过 Java 程序一次性导入。

  • 有效的经度从 -180 度到 180 度。有效的纬度从 -85.05112878 度到 85.05112878 度。

  • 当坐标位置超出指定范围时,该命令将会返回一个错误。

  • 已经添加的数据,是无法再次往里面添加的。

geopos
  • 格式:geopos [member…] 获得指定地区的坐标值

geopos

geodist
  • 格式:geodist [m|km|ft|mi ] 获取两个位置之间的直线距离

geodist

单位:

m 表示单位为米[默认值]。

km 表示单位为千米。

mi 表示单位为英里。

ft 表示单位为英尺。

如果用户没有显式地指定单位参数, 那么 GEODIST 默认使用米作为单位

georadius

格式:georadius< longitude>radius m|km|ft|mi 以给定的经纬度为中心,找出某一半径内的元素

m|km|ft|mi :经度 纬度 距离 单位

georadius

Redis的配置文件

redis.conf

  • Redis的安装根目录下(/opt/redis-5.0.2),Redis在启动时会加载这个配置文件,在运行时按照配置进行工作。 这个文件有时候我们会拿出来,单独存放在某一个位置,启动的时候必须明确指定使用哪个配置文件,此文件才会生效。

网络配置

  • bind:绑定IP地址,其它机器可以通过此IP访问Redis,默认绑定127.0.0.1,也可以修改为本机的IP地址。

  • port:配置Redis占用的端口,默认是6379。

  • tcp-keepalive:TCP连接保活策略,可以通过tcp-keepalive配置项来进行设置,单位为秒,假如设置为60秒,则server端会每60秒向连接空闲的客户端发起一次ACK请求,以检查客户端是否已经挂掉,对于无响应的客户端则会关闭其连接。如果设置为0,则不会进行保活检测。

常规配置

  • loglevel:日志级别,开发阶段可以设置成debug,生产阶段通常设置为notice或者warning.

  • logfile:指定日志文件名,如果不指定,Redis只进行标准输出。要保证日志文件所在的目录必须存在,文件可以不存在。还要在redis启动时指定所使用的配置文件,否则配置不起作用。

  • databases:配置Redis数据库的个数,默认是16个。

安全配置

  • requirepass:配置Redis的访问密码。默认不配置密码,即访问不需要密码验证。此配置项需要在protected-mode=yes时起作用。使用密码登录客户端:redis-cli -h ip -p 6379 -a pwd

Redis持久化

redis是内存数据库,它把数据存储在内存中,这样在加快读取速度的同时也对数据安全性产生了新的问题,即当redis所在服务器发生宕机后,redis数据库里的所有数据将会全部丢失。为了解决这个问题,redis提供了持久化功能——RDBAOF(Append Only File)。

RDB配置

  • save :配置复合的快照触发条件,即Redis 在seconds秒内key改变changes次,Redis把快照内的数据保存到磁盘中一次。默认的策略是:

    • 1分钟内改变了1万次

    • 或者5分钟内改变了10次

    • 或者15分钟内改变了1次

      如果要禁用Redis的持久化功能,则把所有的save配置都注释掉。

  • stop-writes-on-bgsave-error:当bgsave快照操作出错时停止写数据到磁盘,这样能保证内存数据和磁盘数据的一致性,但如果不在乎这种一致性,要在bgsave快照操作出错时继续写操作,这里需要配置为no。

  • rdbcompression:设置对于存储到磁盘中的快照是否进行压缩,设置为yes时,Redis会采用LZF算法进行压缩;如果不想消耗CPU进行压缩的话,可以设置为no,关闭此功能。

  • rdbchecksum:在存储快照以后,还可以让Redis使用CRC64算法来进行数据校验,但这样会消耗一定的性能,如果系统比较在意性能的提升,可以设置为no,关闭此功能。

  • dbfilename:Redis持久化数据生成的文件名,默认是dump.rdb,也可以自己配置。

  • dir:Redis持久化数据生成文件保存的目录,默认是./即redis的启动目录,也可以自己配置。

RDB策略:在指定时间间隔内,redis服务执行指定次数的写操作,会自动触发一次持久化操作。

RDB策略是redis默认的持久化策略,redis服务开启时这个持久化策略就已经默认开启了。

AOF配置

  • appendonly:配置是否开启AOF,yes表示开启,no表示关闭。默认是no。

  • appendfilename:AOF保存文件名

  • appendfsync:AOF异步持久化策略

    • always:同步持久化,每次发生数据变化会立刻写入到磁盘中。性能较差但数据完整性比较好(慢,安全)
    • everysec:出厂默认推荐,每秒异步记录一次(默认值)
    • no:不即时同步,由操作系统决定何时同步。
  • no-appendfsync-on-rewrite:重写时是否可以运用appendsync,默认no,可以保证数据的安全性。

  • auto-aof-rewrite-percentage:设置重写的基准百分比

  • auto-aof-rewrite-min-size:设置重写的基准值

采用操作日志来记录进行每一次写操作,每次redis服务启动时,都会重新执行一遍操作日志中的指令。

效率低下,redis默认不开启AOF功能。

小结

根据数据的特点决定开启那种持久化策略,一般情况,使用默认的开启RDB策略就够了。

Redis事务

Redis的事务允许在一次单独的步骤中执行一组命令,并且能够保证将一个事务中的所有命令序列化,然后按顺序执行;在一个Redis事务中,Redis要么执行其中的所有命令,要么什么都不执行。即Redis的事务要能够保证序列化和原子性。

Redis事务常用命令

multi
  • 语法:multi

  • 功能:用于标记事务块的开始。Redis会将后续的命令逐个放入队列中,然后才能使用EXEC命令原子化地执行这个命令序列。

返回值:开启成功返回OK

multi

exec
  • 语法:exec

  • 功能:在一个事务中执行所有先前放入队列的命令,然后恢复正常的连接状态。

    • 如果在把命令压入队列的过程中报错,则整个队列中的命令都不会执行,执行结果报错;
    • 如果在压队列的过程中正常,在执行队列中某一个命令报错,则只会影响本条命令的执行结果,其它命令正常运行;
    • 当使用WATCH命令时,只有当受监控的键没有被修改时,EXEC命令才会执行事务中的命令;而一旦执行了exec命令,之前加的所有watch监控全部取消。

返回值:这个命令的返回值是一个数组,其中的每个元素分别是原子化事务中的每个命令的返回值。 当使用WATCH命令时,如果事务执行中止,那么EXEC命令就会返回一个Null值。

exec

discard
  • 语法:discard

  • 功能:清除所有先前在一个事务中放入队列的命令,并且结束事务。如果使用了WATCH命令,那么DISCARD命令就会将当前连接监控的所有键取消监控。

返回值:清除成功,返回OK。

discard

事务冲突问题

一个请求想给金额减8000

一个请求想给金额减5000

一个请求想给金额减1000

不加事务

悲观锁

悲观锁(Pessimistic Lock), 顾名思义,就是很悲观,每次去拿数据的时候都认为别人会修改,所以每次在拿数据的时候都会上锁,这样别人想拿这个数据就会block直到它拿到锁。传统的关系型数据库里边就用到了很多这种锁机制,比如行锁表锁等,读锁写锁等,都是在做操作之前先上锁。

悲观锁

乐观锁

乐观锁(Optimistic Lock), 顾名思义,就是很乐观,每次去拿数据的时候都认为别人不会修改,所以不会上锁,但是在更新的时候会判断一下在此期间别人有没有去更新这个数据,可以使用版本号等机制。乐观锁适用于多读的应用类型,这样可以提高吞吐量。Redis就是利用这种check-and-set机制实现事务的。

乐观锁

watch
  • 语法:watch key [key …]

  • 功能:当某个事务需要按条件执行时,就要使用这个命令将给定的键设置为受监控的。如果被监控的key值在本事务外有修改时,则本事务所有指令都不会被执行。Watch命令相当于关系型数据库中的乐观锁。

返回值:监控成功,返回OK。

watch

unwatch
  • 语法:unwatch

  • 功能:清除所有先前为一个事务监控的键。如果在watch命令之后你调用了EXEC或DISCARD命令,那么就不需要手动调用UNWATCH命令。

返回值:清除成功,返回OK。

总结

  • 单独的隔离操作:事务中的所有命令都会序列化、顺序地执行。事务在执行过程中,不会被其它客户端发来的命令请求所打断,除非使用watch命令监控某些键。

  • 不保证事务的原子性:redis同一个事务中如果一条命令执行失败,其后的命令仍然可能会被执行,redis的事务没有回滚。Redis已经在系统内部进行功能简化,这样可以确保更快的运行速度,因为Redis不需要事务回滚的能力。

Redis消息的发布与订阅(了解)

Redis 发布订阅(pub/sub)是一种消息通信模式:发送者(pub)发送消息,订阅者(sub)接收消息。Redis 客户端可以订阅任意数量的频道。

发布订阅示意图

图一:消息订阅者(client2 、 client5 和 client1)订阅频道 channel1:

消息订阅者

图二:消息发布者发布消息到频道channel1,会被发送到三个订阅者:

消息发布者

常用命令

subscribe
  • 语法:subscribe channel [channel…]

  • 功能:订阅一个或多个频道的信息

返回值:订阅的消息

subscribe

publish
  • 语法:publish chanel message

  • 功能:将信息发送到指定的频道。

返回值:数字。接收到消息订阅者的数量。

publish

psubscribe
  • 语法:psubscribe pattern [pattern]

  • 功能:订阅一个或多个符合给定模式的频道。模式以 * 作为通配符,例如:news.* 匹配所有以 news. 开头的频道。

返回值:订阅的信息。

psubscribe

Redis的主从复制

主机数据更新后根据配置和策略,自动同步到从机的master/slave机制,Master以写为主,Slave以读为主。

主少从多,主写从读,读写分离,主写同步复制到从

TODO

Redis哨兵模式

TODO

详情请参考文档(尚硅谷和动力节点)阿里云盘有

Jedis

代码编写

注入jedis依赖

<dependencies>
    <dependency>
        <groupId>redis.clients</groupId>
        <artifactId>jedis</artifactId>
    </dependency>
    <dependency>
        <groupId>junit</groupId>
        <artifactId>junit</artifactId>
    </dependency>

</dependencies>
  • 测试能否连通
/**
 * 本机测试
 */
@Test
public void test01() {
    Jedis jedis = new Jedis("127.0.0.1", 6379);
    String ping = jedis.ping();
    System.out.println(ping);
}
/**
 * 虚拟机测试
 */
@Test
public void test02(){
    Jedis jedis = new Jedis("192.168.174.131",6379);
    jedis.auth("123456");
    System.out.println(jedis.ping());
}
  • 禁用Linux的防火墙:Linux(CentOS7)里执行命令

    • systemctl stop/disable firewalld.service
  • redis.conf中注释掉: bind 127.0.0.1 ,然后关闭保护模式:protected-mode no

Jedis常用操作


public class JedisDemo1 {

    /**
     * 本机测试
     */
    @Test
    public void test01() {
        Jedis jedis = new Jedis("127.0.0.1", 6379);
        String ping = jedis.ping();
        System.out.println(ping);
    }

    /**
     * 虚拟机测试
     */
    @Test
    public void test02() {
        Jedis jedis = new Jedis("192.168.174.131", 6379);
        jedis.auth("123456");
        System.out.println(jedis.ping());
    }

    /**
     * Jedis基本操作 string
     */
    @Test
    public void test03() {
        Jedis jedis = new Jedis("127.0.0.1", 6379);
        jedis.set("k1", "v1");
        jedis.set("k2", "v2");
        // 设置多个key-value
        jedis.mset("k3", "v3", "k4", "v4");
        System.out.println(jedis.mget("k3", "k4"));
        System.out.println(jedis.get("k1"));

        for (String key : jedis.keys("*")
        ) {
            System.out.println(key);
        }
        //
    }

    /**
     * 操作list
     */
    @Test
    public void test04() {
        Jedis jedis = new Jedis("127.0.0.1", 6379);
        jedis.lpush("mylist", "hxl", "ssm", "zs");
        List<String> list = jedis.lrange("mylist", 0, -1);
        for (String element : list) {
            System.out.println(element);
        }
    }

    /**
     * 操作set
     */
    @Test
    public void test05() {
        Jedis jedis = new Jedis("127.0.0.1", 6379);
        jedis.sadd("name", "hxl", "ssm", "zs");
        Set<String> name = jedis.smembers("name");
        System.out.println(name);
    }

    /**
     * 操作hash
     */
    @Test
    public void test06() {
        Jedis jedis = new Jedis("127.0.0.1", 6379);
        jedis.hset("users", "age", "20");
        System.out.println(jedis.hget("users", "age"));

        jedis.hset("hash1", "userName", "lisi");
        System.out.println(jedis.hget("hash1", "userName"));
        Map<String, String> map = new HashMap<String, String>();
        map.put("telphone", "13810169999");
        map.put("address", "atguigu");
        map.put("email", "abc@163.com");
        jedis.hmset("hash2", map);
        List<String> result = jedis.hmget("hash2", "telphone", "email", "address");
        System.out.println(result);
        for (String element : result) {
            System.out.println(element);
        }

    }

    /**
     * 操作zset
     */
    @Test
    public void test07() {
        Jedis jedis = new Jedis("127.0.0.1", 6379);
        jedis.zadd("score", 100d, "少司命");
        System.out.println(jedis.zrange("score", 0, -1));
    }

}

更多操作参考常用命令使用

模拟短信发送

package com.ssm.Demo;

import redis.clients.jedis.Jedis;

import java.util.Random;

/**
 * @author shaoshao
 * @version 1.0
 * @date 2022/4/17 16:04
 */
public class PhoneCode {
    public static void main(String[] args) {

//        verifyCode("19858165529");
        getRedisCode("19858165529","098883");
    }



    //生成6位数字验证码
    public static StringBuffer getCode() {
        Random random = new Random();
//        String code = "";
        StringBuffer code = new StringBuffer();
        for (int i = 0; i < 6; i++) {
            int rand = random.nextInt(10);
            code.append(rand);
        }
        return code;
    }

    // 每个手机每天发送3个验证码,验证码放到redis中,设置过期时间
    public static String verifyCode(String phone) {
        Jedis jedis = new Jedis("127.0.0.1",6379);

        // 手机发送次数key
        String countKey = "VerifyCode"+phone+":count";
        // 验证码key
        String codeKey = "VerifyCode"+phone+":code";

        String count = jedis.get(countKey);
        if (count == null){
            // 第一次发送
            // 设置发送次数是1
            jedis.setex(countKey,24*60*60,"1");
        } else if (Integer.parseInt(count)<=2){
            jedis.incr(countKey);
        } else if (Integer.parseInt(count)>2){
            System.out.println("发送次数超过三次");
            jedis.close();
        }
        // 发送验证码到redis里面
        String vcode = getCode().toString();
        jedis.setex(codeKey,120,vcode);
        jedis.close();
        return vcode;
    }

    // 验证码校验
    public static void getRedisCode(String phone,String code){
        Jedis jedis = new Jedis("127.0.0.1",6379);
        // 验证码key
        String codeKey = "VerifyCode"+phone+":code";
        String redisCode = jedis.get(codeKey);
        System.out.println(redisCode);
        if (redisCode.equals(code)){
            System.out.println("成功");
        } else {
            System.out.println("失败");
        }
        jedis.close();
    }
}

SpringBoot整合Redis

pom.xml

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <groupId>com.ssm</groupId>
    <artifactId>jedisspringboot</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <name>jedisspringboot</name>
    <description>Demo project for Spring Boot</description>

    <properties>
        <java.version>1.8</java.version>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
        <spring-boot.version>2.3.7.RELEASE</spring-boot.version>
    </properties>

    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-redis</artifactId>
        </dependency>
        <!-- spring2.X集成redis所需common-pool2-->
        <dependency>
        <groupId>org.apache.commons</groupId>
            <artifactId>commons-pool2</artifactId>
            <version>2.6.0</version>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
            <exclusions>
                <exclusion>
                    <groupId>org.junit.vintage</groupId>
                    <artifactId>junit-vintage-engine</artifactId>
                </exclusion>
            </exclusions>
        </dependency>
    </dependencies>

    <dependencyManagement>
        <dependencies>
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-dependencies</artifactId>
                <version>${spring-boot.version}</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>
        </dependencies>
    </dependencyManagement>

    <build>
        <plugins>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-compiler-plugin</artifactId>
                <version>3.8.1</version>
                <configuration>
                    <source>1.8</source>
                    <target>1.8</target>
                    <encoding>UTF-8</encoding>
                </configuration>
            </plugin>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
                <version>2.3.7.RELEASE</version>
                <configuration>
                    <mainClass>com.ssm.JedisspringbootApplication</mainClass>
                </configuration>
                <executions>
                    <execution>
                        <id>repackage</id>
                        <goals>
                            <goal>repackage</goal>
                        </goals>
                    </execution>
                </executions>
            </plugin>
        </plugins>
    </build>

</project>

RedisConfig


@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;
    }
}

RedisTestController


@RestController
@RequestMapping("/redisTest")
public class RedisTestController {
    @Autowired
    private RedisTemplate redisTemplate;

    @GetMapping
    public String testRedis() {
        //设置值到redis
        redisTemplate.opsForValue().set("name","lucy");
        //从redis获取值
        String name = (String)redisTemplate.opsForValue().get("name");
        return name;
    }
}

JedisspringbootApplication

package com.ssm;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

@SpringBootApplication
public class JedisspringbootApplication {

    public static void main(String[] args) {
        SpringApplication.run(JedisspringbootApplication.class, args);
    }

}

application.properties

# 应用名称
#Redis服务器地址
spring.redis.host=127.0.0.1
#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

文章作者: shaoshaossm
版权声明: 本博客所有文章除特別声明外,均采用 CC BY 4.0 许可协议。转载请注明来源 shaoshaossm !
评论
  目录