Redis笔记

Redis(Remote dictionary server)开源的基于内存的数据存储系统

可用于数据库、缓存、队列等各种场景。

支持key-value的储存形式,底层是用C语言编写的。

基于key-value形式的数据字典,结构非常简单,没有数据表的概念,之间用键值对的形式完成数

据的管理。

SQL NoSQL
数据结构结构化(Structured)非结构化
数据关联关联的(Relational)无关联的
查询方式SQl查询非SQL
事务特性ACIDBASE
储存方式磁盘内存
扩展性垂直水平
使用场景

1)数据结构固定

2)相关业务对数据安全性、一致性要求较高

1)数据结构不固定

2)对一致性、安全性要求不高

3)对性能要求


Redis的特征       

  • 性能极高

  • 键值型(Key--Value)、Value支持多种不同数据结构、功能丰富。

  • 单线程、每个命令具备原子性

  • 低延迟、速度快(基于内存、IO多路复用、良好的编码)

  • 数据类型丰富、单键值对最大支持521M大小的数据

  • 简单易用,支持所有的主流语言

  • 支持数据持久化,主从复制,哨兵模式等高可用特性


Redis的数据结构

基本数据结构:

  • 字符串 String
  • 列表 Lsit
  • 集合 Set
  • 有序集合 SortedSet(ZSet)
  • 哈希 Hash    key:{  key:value   }

高级数据结构:

  • 消息队列 Stream
  • 地理空间 Geospatial
  • HyperLogLog
  • 位图 Bitmap
  • 位域 Bitfield

Redis的三种使用方式

        CLI(Command Line Interface)命令行界面
        API(Application Programming Interface)编程使用指定方法
        GUI(Graphical User Interface)可视化软件

Redis基本命令

SELECT:切换数据库。例:SELECT 2

DBSIZE:查看数据库中的内容。

FLUSHDB:清空当前数据库。(FLUSHALL---清空所有数据库)

MOVE:将当前数据库的Key移动到制定的数据库。例:MOVE name 1 


String(字符串)

  • String类型的使用场景:Value除了是字符串也可以是数字!
    • 计数器
    • 统计多单位的数量
    • 粉丝数
    • 对象缓存存储

TYPE:查看当前key的类型。例:TYPE name     

APPEND:向key后面追加一个字符串。例:APPEND key1 “Hello”

STRLEN:获取字符串的长度。例:STRLEN

Redis中的键和值都是以二进制的形式存储的,默认不支持中文的,可以先quit退出Redis,然后redis-cli --raw表示以原始的形式来显示内容

SET Key Value :设置一个键值。

name与Name的值不一样(Redis中的键区分大小写,Redis默认都是使用字符串来存储数据,且是二进制安全的)

GET: 获取键的值。

DEL :删除一个键 。

EXISTS: 来判断一个键是否存在。(存在为1不存在为0)

KEYS: 用来查看数据库中都有哪些键。例:KEYS * (用来查找数据库中所有的键)、KEYS *me(查找所以以me结尾的键) 

CLEAR: 清空屏幕

127.0.0.1:6379> set key1 v1     #设置值
OK
127.0.0.1:6379> get key1        #获取值
v1
127.0.0.1:6379> keys *          #获取所有的key
key1
127.0.0.1:6379> EXISTS key1     #判断某一个key是否存在
1
127.0.0.1:6379> APPEND key1 "hello"    #追加字符串,如果当前key不存在,就相当于setkey
7
127.0.0.1:6379> get key1        
v1hello
127.0.0.1:6379> STRLEN key1      #获取字符串长度的长度!
7
127.0.0.1:6379> APPEND key1 "world"    
12
127.0.0.1:6379> STRLEN key1
12
127.0.0.1:6379> get key1
v1helloworld


######################################################################################
127.0.0.1:6379> set views 0         #初始化浏览量为0
OK
127.0.0.1:6379> get views           
0
127.0.0.1:6379> incr views          #自增1  浏览量+1
1
127.0.0.1:6379> incr views
2
127.0.0.1:6379> get views
2
127.0.0.1:6379> decr views           #自减1   浏览量-1
1
127.0.0.1:6379> decr views
0
127.0.0.1:6379> decr views
-1
127.0.0.1:6379> get views
-1
127.0.0.1:6379> INCRBY views 10       #指定步长,指定增量! 浏览量+10
9
127.0.0.1:6379> INCRBY views 10       #指定步长,指定减量! 浏览量-10
19
127.0.0.1:6379> DECRBY views 10
9
127.0.0.1:6379> get views
9
######################################################################################


# 字符串范围
127.0.0.1:6379> set key1 "hello,world"    #设置key1的值
OK
127.0.0.1:6379> get key1
hello,world
127.0.0.1:6379> GETRANGE key1 0 3         #截取字符串[0,3]
hell
127.0.0.1:6379> GETRANGE key1 0 -1        #获取全部的字符串 和get key是一样的
hello,world


# 替换!
127.0.0.1:6379> set key2 abcdefg        
OK
127.0.0.1:6379> get key2
abcdefg
127.0.0.1:6379> SETRANGE key2 1 xx        #替换自定位置开始的字符串!
7
127.0.0.1:6379> get key2
axxdefg

######################################################################################

TTL: 查看一个键的过期时间。(-1表示没有设置过期时间,-2表示已经过期)。例:TTL name

127.0.0.1:6379> TTL name
-1
127.0.0.1:6379>

EXPIRE: 来设置一个键的过期时间。例:EXPIRE name 10 (设置name键的过期时间为10秒,同时GET和KEYS也获取不到此键)

127.0.0.1:6379> EXPIRE name 10
1
127.0.0.1:6379> TTL name
8
127.0.0.1:6379> TTL name
2
127.0.0.1:6379> TTL name
0
127.0.0.1:6379> TTL name
-2
127.0.0.1:6379> GET name

127.0.0.1:6379> KEYS *

127.0.0.1:6379>

SETEX: 设置一个带有过期时间的键值对 例:SETEX name 10 hello(设置一个值为hello键为name过期时间为10秒的键值对)

127.0.0.1:6379> SETEX name 10 hello
OK
127.0.0.1:6379>
127.0.0.1:6379> TTL name
7
127.0.0.1:6379> TTL name
4
127.0.0.1:6379> TTL name
-2
127.0.0.1:6379> GET name

127.0.0.1:6379> KEYS *

127.0.0.1:6379>

SETNX: 只有当键不存在时才设置键的值,否则不会做任何动作

127.0.0.1:6379> SETNX name hello
1
127.0.0.1:6379> SETNX name hhh
0
127.0.0.1:6379> GET name
hello
127.0.0.1:6379>

MEST: 同时设置多个值。

MGET: 同时获取多个值。

127.0.0.1:6379> mset k1 v1 k2 v2 k3 v3    #同时设置多个值
OK
127.0.0.1:6379> keys *
k2
k1
k3
127.0.0.1:6379> mget k1 k2 k3            #同时获取多个值
v1
v2
v3
127.0.0.1:6379> msetnx k1 v1 k4 v4       #msetnx 是一个原子性的操作,要么一起成功,要么一起失败
0
127.0.0.1:6379> get k4

 MSET对象

SET user:1 {name:zhangsan,age:3} #设置一个user:1对象 值为json字符来保存一个对象!

# 这里的key是一个巧妙的设计:user:{id}:{filed},如此设计在Redis中完全OK!

127.0.0.1:6379> mset user:1:name zhangsan user:1:age 18
OK
127.0.0.1:6379> mget user:1:name user:1:age
1) "zhangsan"
2) "18"

GETSET:先get再set 

127.0.0.1:6379> GETSET db redis    # 如果不存在值,则返回nil
(nil)
127.0.0.1:6379> get db
"redis"
127.0.0.1:6379> GETSET db Mongodb    # 如果存在值,获取原来的值,并设置新的值
"redis"
127.0.0.1:6379> get db
"Mongodb"

数据结构是相通的 !


List的常用命令(所有的list命令都是以 “ L ” 开头)

LPUSH: 从列表的头部添加元素,可同时添加多个元素 。

RPUSH:从列表的尾部添加元素,也可同时添加多个元素。

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    #获取list中的值
1) "three"
2) "two"
3) "one"
127.0.0.1:6379> LRANGE list 0 1    #通过区间获取具体的值
1) "three"
2) "two"
127.0.0.1:6379> RPUSH list right    #将一个或者多个值,插入到列表的尾部(右)
(integer) 4
127.0.0.1:6379> 
127.0.0.1:6379> LRANGE list 0 -1
1) "three"
2) "two"
3) "one"
4) "right"

LPOP:删除列表中第一一个元素,并返回被删除的元素

RPOP:删除列表中最后一个元素,并返回被删除的元素

LPOP、RPOP也可以一次性删除多个元素。例:LPOP letter 2(表示从列表头部删除2个元素,RPOP也同理)

可以使用LPUSH在列表头部添加元素,再使用RPOP在列表尾部删除一个元素,就实现了一个最简单的先进先出队列

127.0.0.1:6379> LRANGE list 0 -1
1) "three"
2) "two"
3) "one"
4) "right"
127.0.0.1:6379> LPOP list     # 移除list的第一个元素
"three"
127.0.0.1:6379> Rpop list     # 移除list的最后一个元素
"right"
127.0.0.1:6379> LRANGE list 0 -1
1) "two"
2) "one"

LRANGE:获取列表的内容。例:LRANGE letter 0(起始位置与结束位置都是以0开始)-1(表示最后一个元素)

127.0.0.1:6379> LRANGE letter 0 -1
e
d
c
b
a
127.0.0.1:6379>

LINDEX:通过下标获得list中的某一个值

127.0.0.1:6379> LINDEX list 1     # 通过下标获取list中的某一个值
"one"
127.0.0.1:6379> LINDEX list 0
"two"

LLEN:查看列表的长度 。例:LLEN letter

127.0.0.1:6379> LLEN letter
4
127.0.0.1:6379>

LREM:移除列表中指定的值。 通常都是移除后面PUSH进来的Value

127.0.0.1:6379> LREM list 1 one        #移除list集合中指定个数的Value,精确匹配
(integer) 1
127.0.0.1:6379> LRANGE list 0 -1
1) "three"
2) "two"
3) "two"
4) "one"
127.0.0.1:6379> LREM list 1 two
(integer) 1
127.0.0.1:6379> LRANGE list 0 -1
1) "three"
2) "two"
3) "one"

LTRIM:删除列表中制定范围以外的元素。例:LTRIM letter 1 3(删除列表中索引为1-3以外的元素)

127.0.0.1:6379> Rpush list "hello"
(integer) 1
127.0.0.1:6379> Rpush list "hello1"
(integer) 2
127.0.0.1:6379> Rpush list "hello2"
(integer) 3
127.0.0.1:6379> Rpush list "hello3"
(integer) 4
127.0.0.1:6379> Ltrim list 1 2       # 通过下标截取指定的长度,这个list已经被改变了(截断了),只剩下截取后的元素!
OK
127.0.0.1:6379> LRANGE list 0 -1
1) "hello1"
2) "hello2"

 RPOPLPUSH:移除列表的最后一个元素,将他移动到新的列表中。

127.0.0.1:6379> Rpush list "hello"
(integer) 1
127.0.0.1:6379> Rpush list "hello1"
(integer) 2
127.0.0.1:6379> Rpush list "hello2"
(integer) 3
127.0.0.1:6379> Rpush list "hello3"
(integer) 4
127.0.0.1:6379> RPOPLPUSH list mylist        # 移除列表的最后一个元素,并将他移动到新的列表中!
"hello3"
127.0.0.1:6379> LRANGE list 0 -1             # 查看原来的列表
1) "hello"
2) "hello1"
3) "hello2"
127.0.0.1:6379> LRANGE mylist 0 -1           #查看目标列表中,确实存在该值!
1) "hello3"

LSET:将列表中指定下标的值替换成另外一个值,更新操作。

127.0.0.1:6379> EXISTS list        # 判断这个列表是否存在
(integer) 0
127.0.0.1:6379> LSET list 0 item    # 如果不存在列表,更新就会报错
(error) ERR no such key
127.0.0.1:6379> LPUSH list value1
(integer) 1
127.0.0.1:6379> LRANGE list 0 0
1) "value1"
127.0.0.1:6379> LSET list 0 item    # 如果存在,就会更新当前下标的值
OK
127.0.0.1:6379> LRANGE list 0 0
1) "item"
127.0.0.1:6379> LSET list 1 hello    # 如果不存在,则会报错!
(error) ERR index out of range

LINSERT: 将某个具体的value插入到列表中某个元素的前面或者后面。

127.0.0.1:6379> RPUSH list "hello"
(integer) 1
127.0.0.1:6379> RPUSH list "world"
(integer) 2
127.0.0.1:6379> LINSERT list before "world" "other"    # 将other插入到world的前面(before)
(integer) 3
127.0.0.1:6379> LRANGE list 0 -1
1) "hello"
2) "other"
3) "world"
127.0.0.1:6379> LINSERT list after world new            # 将new插入到world的后面(new)
(integer) 4
127.0.0.1:6379> LRANGE list 0 -1
1) "hello"
2) "other"
3) "world"
4) "new"

总结 :

  • 实际上是一个链表,before Node after,left,right都可以插入值
  • 如果key不存在,创建新的链表
  • 如果key存在,新增内容
  • 如果移除了所有值,空链表,也代表不存在!
  • 在两边插入或者修改值,效率最高!中间元素,相对来说效率会低一点~ 

Set 集合命令(无序集合且元素不可重复,set相关的命令都是以 “ S ” 开头)

SADD:表示向set中添加元素。例: SADD course Redis Java Linux Redis

SMEMBERS: 查看集合中的元素。例:SMEMBERS course

SISMEMBER:判断元素是否在集合中。例:SISMEMBER courser Redis(输出是1表示在集合中,输出为0表示不在集合中)

127.0.0.1:6379> SADD list hello
(integer) 1
127.0.0.1:6379> SADD list world
(integer) 1
127.0.0.1:6379> SADD list redis
(integer) 1
127.0.0.1:6379> SMEMBERS list    #查看指定set中的所有值
1) "hello"
2) "world"
3) "redis"
127.0.0.1:6379> 
127.0.0.1:6379> SISMEMBER list redis    # 判断一个值是不是在set集合中!
(integer) 1
127.0.0.1:6379> 
127.0.0.1:6379> SISMEMBER list nihao
(integer) 0

SREM:移除set集合中指定的元素。

127.0.0.1:6379> SREM list hello
(integer) 1
127.0.0.1:6379> SMEMBERS list
1) "world"
2) "redis"

SCARD:获取set集合中的个数。

127.0.0.1:6379> SCARD list
(integer) 3

SRANDMEMBER: 随机从set集合中抽出一个元素。

127.0.0.1:6379> SMEMBERS list
1) "world"
2) "redis"
127.0.0.1:6379> SRANDMEMBER list        # 随机抽选出一个元素
"redis"
127.0.0.1:6379> SRANDMEMBER list
"world"
127.0.0.1:6379> SRANDMEMBER list 2       # 随机抽选出制定个数的元素
1) "world"
2) "redis"

 SPOP:随机删除一些set集合中的元素!

127.0.0.1:6379> SMEMBERS list
1) "world"
2) "redis"
3) "Java"
4) "Linux"
127.0.0.1:6379> SPOP list        # 随机移除一些set集合中的元素!
"world"
127.0.0.1:6379> SPOP list
"Java"
127.0.0.1:6379> SMEMBERS list
1) "redis"
2) "Linux"

 SMOVE:将set集合一个指定的值,移动到另一个set集合中!

127.0.0.1:6379> SADD list hello
(integer) 1
127.0.0.1:6379> SADD list world
(integer) 1
127.0.0.1:6379> SADD list redis
(integer) 1
127.0.0.1:6379> SMEMBERS list
1) "hello"
2) "world"
3) "redis"
127.0.0.1:6379> SADD list2 newlist
(integer) 1
127.0.0.1:6379> SMEMBERS list2
1) "newlist"
127.0.0.1:6379> SMOVE list list2 world     # 将list中world的值移动到list2集合中
(integer) 1
127.0.0.1:6379> SMEMBERS list2
1) "newlist"
2) "world"

 SDIFF:差集。

SINTER:交集。

SUNION:并集。

127.0.0.1:6379> SADD key1 a
(integer) 1
127.0.0.1:6379> SADD key1 b
(integer) 1
127.0.0.1:6379> SADD key1 c
(integer) 1
127.0.0.1:6379> SADD key2 c
(integer) 1
127.0.0.1:6379> SADD key2 d
(integer) 1
127.0.0.1:6379> SADD key2 e
(integer) 1
127.0.0.1:6379> SDIFF key1 key2        # 差集
1) "a"
2) "b"
127.0.0.1:6379> SINTER key1 key2       # 交集    共同好友可以这样实现
1) "c"
127.0.0.1:6379> SUNION key1 key2       # 并集
1) "a"
2) "b"
3) "c"
4) "d"
5) "e"


SortedSet(ZSet)

有序集合  每个元素都会关联一个浮点类型的分数,然后按照这个分数来对集合中的元素进行从小到大的排序,元素是唯一的但是分数是可以重复的,有序集合的相关命令都是以 “ Z ” 开头的

ZADD:向有序集合中添加元素。例:ZADD result 680 清华 660 北大 650 复旦 640 浙大(分数在前,元素在后)

ZRANGE:查看集合中的元素。例:ZRANGE result 0 -1 WITHSCORES(WITHSCORES 输出元素的时候输出分数)

127.0.0.1:6379> ZADD salary 2500 xiaohong        # 添加三个用户
(integer) 1
127.0.0.1:6379> ZADD salary 5000 zhangsan
(integer) 1
127.0.0.1:6379> ZADD salary 2000 xiaoming
(integer) 1
127.0.0.1:6379> ZRANGEBYSCORE salary -inf +inf     # 显示所有用户 从小到大!
1) "xiaoming"
2) "xiaohong"
3) "zhangsan"
127.0.0.1:6379> ZRANGEBYSCORE salary -inf +inf
1) "xiaoming"
2) "xiaohong"
3) "zhangsan"
127.0.0.1:6379> ZRANGEBYSCORE salary -inf +inf withscores       # 显示全部的用户并且附带成绩
1) "xiaoming"
2) "2000"
3) "xiaohong"
4) "2500"
5) "zhangsan"
6) "5000"
127.0.0.1:6379> ZRANGEBYSCORE salary -inf 2500 withscores    #显示工资小于2500员工的升序排列
1) "xiaoming"
2) "2000"
3) "xiaohong"
4) "2500"

ZSCORE:查看元素的分数

> ZSCORE result 清华
"680"

ZRANK:查看元素从小到大排序后的下标

> ZRANK result 清华
(integer) 3

ZREVRANK:反转。例:ZREVRANK result 清华(查看清华从大到小排序后的下标)

> ZRANK result 清华
(integer) 3

> ZREVRANK result 清华
(integer) 0

Hash(哈希)

(Map集合 key{map},值是一个map集合,适合用来存储对象,相关的命令都是以 “ H ” 开头)

本质和String类型没有太大区别,还是一个简单的key-value

HSET:向哈希中添加一个键值对。

HGET:来获取哈希中某个键值对。

HMSET:设置多个key-value

HMGET:获取多个key

HGETALL:来获取整个哈希中所有的键值对,name是键,hy是值

127.0.0.1:6379> HSET myhash field1 hello     # set一个具体的 key-value
(integer) 1
127.0.0.1:6379> HGET myhash field1        #获取一个字段值
"hello"
127.0.0.1:6379> HMSET myhash field1 world field2 redis        #set多个key-value
OK
127.0.0.1:6379> HMGET myhash field1 field2        #获取多个字段
1) "world"
2) "redis"
127.0.0.1:6379> HGETALL myhash        #获取全部数据
1) "field1"
2) "world"
3) "field2"
4) "redis"

HDEL:删除hash中指定的key字段,对应的value也就消失了 

> HDEL person age
(integer) 1

> HGETALL person
1) "name"
2) "hy"

HEXISTS:判断某个键值对是否存在。(1表示存在,0表示不存在)

> HEXISTS person name
(integer) 1

> HEXISTS person age
(integer) 0

HKEYS:获取哈希中的所有字段

HVALS:获取所有的的value

> HKEYS person
1) "name"

HLEN:获取哈希中所有的键值对的数量

> HLEN person
(integer) 1


Stream(消息队列)轻量级的消息队列,相关的命令以 “ S ” 开头

XADD::向Streamm中添加消息。例:XADD hy * course redis(  * 表示自动生成一个消息ID 并且会保证生成的ID是递增的 )

回显的信息(1722853636808-0)就是消息的ID

ID的格式是 整数-整数(1-0)1表示时间戳 0表示一个序列号

如果手动指定ID的话,就需要自己来保证这个ID的递增

> XADD hy * courser redis
1722853636808-0

> XADD hy * courser git
"1722853722649-0"

> XADD hy * courser docker
"1722853727918-0"

SLEN:查看Stream中消息的数量。例:XLEN hy

> XLEN hy
(integer) 3

XRANGE :查看Stream中的消息和详细内容。例:XRANGE hy - +(开始和结束可以使用 - +表示所有的消息)

> XRANGE hy - +
1) 1) "1722853636808-0"
   2) 1) "courser"
      2) "redis"
2) 1) "1722853722649-0"
   2) 1) "courser"
      2) "git"
3) 1) "1722853727918-0"
   2) 1) "courser"
      2) "docker"

XDEL:删除消息。例:XDEL hy 1722853727918-0(对应的是消息的ID)

也可以通过XTRIM命令来执行。例:XTRIM hy MAXLEN 0(MAXLENS 0 表示删除所有的消息)

> XDEL hy 1722853727918-0
(integer) 1

> XRANGE hy - +
1) 1) "1722853636808-0"
   2) 1) "courser"
      2) "redis"
2) 1) "1722853722649-0"
   2) 1) "courser"
      2) "git"

> XTRIM hy MAXLEN 0
(integer) 2

> XRANGE hy - +
(empty list or set)

SREAD:读取消息。例:SREAD COUNT 2 BLOCK 1000 STREAMS huang 0

(COUNT 2表示读取两条消息,BLOCK 1000---如果没有就阻塞1000毫秒,STREAMS后面加上消息队列的名称)

( 0表示下标 从第一位开始读取,如果比消息队列中下标大 就会阻塞1秒。获取从此刻开始以后的最新消息可以将0改为$)可以重复读取

> XADD huang 1-0 courses git
"1-0"

> XADD huang 2-0 courses docker
"2-0"

> XADD huang 3-0 courses redis
"3-0"

> XREAD COUNT 2 BLOCK 1000 STREAMS huang 0
1) 1) "huang"
   2) 1) 1) "1-0"
         2) 1) "courses"
            2) "git"
      2) 1) "2-0"
         2) 1) "courses"
            2) "docker"

XGROUP:创建消费组。例:XGROUP CREATE hy(消息的名称)group1(组的名称)0(ID)创建了一个名为group1的消费者组 

> XGROUP CREATE hy group1 0
"OK"

XINFO GROUPS:查看消费者组的信息。例:XINFO GROUPS hy(是键值不是组的名称)

> XINFO GROUPS hy
1) 1) "name"
   2) "group1"
   3) "consumers"
   4) "0"
   5) "pending"
   6) "0"
   7) "last-delivered-id"
   8) "0-0"

XGROUP CREATECONSUMER:创建消费者。例:XGROUP CREATECONSUMER hello(消息的名称)group1(组的名称)consumer1(消费者的名称)


 三种特殊数据类型

geospatial 地理位置

        朋友的定位,附近的人,打车距离计算

GEOADD:添加地理位置。(两级(南极与北极)无法直接添加,一般会下载城市数据,直接通过java程序一次性导入!)

参数:key 值(经度、纬度、名称)

有效的经度是-180到180度,有效的纬度是-85.05112878到85.05112878

127.0.0.1:6379> GEOADD china:city 116.40 39.90 beijin
(integer) 1
127.0.0.1:6379> GEOADD china:city 121.47 31.23 shanghai
(integer) 1
127.0.0.1:6379> GEOADD china:city 106.60 29.53 chongqi
(integer) 1
127.0.0.1:6379> GEOADD china:city 114.05 22.52 shengzhen
(integer) 1
127.0.0.1:6379> GEOADD china:city 120.16 30.24 hangzhou
(integer) 1
127.0.0.1:6379> GEOADD china:city 108.96 34.26 xian
(integer) 1

GEOPOS:获取指定的城市的经度和纬度。

127.0.0.1:6379> GEOPOS china:city beijin
1) 1) "116.39999896287918091"
   2) "39.90000009167092543"
127.0.0.1:6379> GEOPOS china:city shanghai xian
1) 1) "121.47000163793563843"
   2) "31.22999903975783553"
2) 1) "108.96000176668167114"
   2) "34.25999964418929977"

GEODIST:返回来两个给定位置之间的距离。

  • m表示单位为m
  • km表示单位为千米
  • mi表示单位为英里
  • ft表示单位为英尺
127.0.0.1:6379> GEODIST china:city beijin xian     # 查看北京到西安的直线距离
"910056.5237"
127.0.0.1:6379> GEODIST china:city beijin xian km    # 查看北京到西安的直线距离 单位为km
"910.0565"
127.0.0.1:6379> GEODIST china:city beijin shanghai
"1067378.7564"
127.0.0.1:6379> GEODIST china:city beijin shanghai km
"1067.3788"

 附近的人(获取所有附近的人的地址,定位!)通过半径来查询!

所有的数据应该录入china:city,才会让结果更加精确!

GEORADIUS:以给定的经纬度为中心,找出某一半径内的元素

# 以110 30 这个经纬度为中心,寻找房源1000km内的城市
127.0.0.1:6379> GEORADIUS china:city 110 30 1000 km     
1) "chongqi"
2) "xian"
3) "shengzhen"
4) "hangzhou"
127.0.0.1:6379> GEORADIUS china:city 110 30 500 km
1) "chongqi"
2) "xian"

# 显示到中心距离的位置
127.0.0.1:6379> GEORADIUS china:city 110 30 500 km withdist    
1) 1) "chongqi"
   2) "332.3998"
2) 1) "xian"
   2) "483.8340"

# 显示出他人的定位信息(经纬度)
127.0.0.1:6379> GEORADIUS china:city 110 30 500 km withcoord    
1) 1) "chongqi"
   2) 1) "106.60000115633010864"
      2) "29.52999957900659211"
2) 1) "xian"
   2) 1) "108.96000176668167114"
      2) "34.25999964418929977"

# 筛选出指定的结果!
127.0.0.1:6379> GEORADIUS china:city 110 30 500 km withdist withcoord count 1    
1) 1) "chongqi"
   2) "332.3998"
   3) 1) "106.60000115633010864"
      2) "29.52999957900659211"
127.0.0.1:6379> GEORADIUS china:city 110 30 500 km withdist withcoord count 2
1) 1) "chongqi"
   2) "332.3998"
   3) 1) "106.60000115633010864"
      2) "29.52999957900659211"
2) 1) "xian"
   2) "483.8340"
   3) 1) "108.96000176668167114"
      2) "34.25999964418929977"
127.0.0.1:6379> GEORADIUS china:city 110 30 500 km withdist withcoord count 3
1) 1) "chongqi"
   2) "332.3998"
   3) 1) "106.60000115633010864"
      2) "29.52999957900659211"
2) 1) "xian"
   2) "483.8340"
   3) 1) "108.96000176668167114"
      2) "34.25999964418929977"

GEORADIUSBYMEMBER:找出位于指定元素周围的其他元素

127.0.0.1:6379> GEORADIUSBYMEMBER china:city beijin 1000 km
1) "beijin"
2) "xian"
127.0.0.1:6379> GEORADIUSBYMEMBER china:city shanghai 400 km
1) "hangzhou"
2) "shanghai"

GEOHASH:返回一个或多个位置元素的Geohash表示。(将返回11个字符的Geohash字符串!)

将二维的经纬度转换为一维的字符串,如果两个字符串越接近,两个距离就越近!

127.0.0.1:6379> GEOHASH china:city beijin shanghai
1) "wx4fbxxfke0"
2) "wtw3sj5zbj0"
127.0.0.1:6379> GEOHASH china:city beijin xian
1) "wx4fbxxfke0"
2) "wqj6zky6bn0"

GEO底层的实现原理其实就是ZSet!可以使用ZSet命令来操作geo!

127.0.0.1:6379> ZRANGE china:city 0 -1
1) "chongqi"
2) "xian"
3) "shengzhen"
4) "hangzhou"
5) "shanghai"
6) "beijin"
127.0.0.1:6379> ZREM china:city beijin
(integer) 1
127.0.0.1:6379> ZRANGE china:city 0 -1
1) "chongqi"
2) "xian"
3) "shengzhen"
4) "hangzhou"
5) "shanghai"

HyperLogLog

基数统计的算法

优点:占用的内存是固定的,2^64不同的元素的基数,只需要12kb的内存!如果要从内存角度来比较的话Hyperloglog首选!

A:{1,2,4,5,7,6}、B:{2,5,6}  基数(不重复的元素的个数)= 3,可以接受误差!

网页的UV(一个人访问一个网址多次,但是还是算作一个人)

传统的方式,set保存用户的id,然后就可以统计set中的元素数量作为标准判断

这个方式如果保存大量的用户id,就会比较麻烦!目的是为了计数,而不是保存用户的id

0.81%错误率! 统计UV任务,可以忽略不计!

127.0.0.1:6379> PFADD mykey a b c d  e f g h i j    # 创建第一组元素 mykey
(integer) 1
127.0.0.1:6379> PFCOUNT mykey        # 统计mykey的元素基数数量
(integer) 10
127.0.0.1:6379> PFADD mykey2 i j z x c v b n m    # 创建第二组元素 mykey
(integer) 1
127.0.0.1:6379> PFCOUNT mykey2
(integer) 9
127.0.0.1:6379> PFMERGE mykey3 mykey mykey2    # 合并两组mykey mykey2 => mykey3 并集
OK
127.0.0.1:6379> PFCOUNT mykey3    # 查看并集的数量
(integer) 15

如果允许容错,可以使用Hyperloglog!如果不允许容错,可以使用set或者自己的数据类型即可!


Bitmaps

位储存

统计用户信息,活跃,不活跃!登录,为登录。两个状态的,都可以使用Bitmaps

Bitmaps位图,数据结构!都是操作二进制位来进行记录,只有 0 和 1 两个状态 

使用Bitmaps 来记录 周一到周日的打卡记录!SETBIT

127.0.0.1:6379> SETBIT sign 0 1     # 0 代表星期一  1 代表已打卡
(integer) 0
127.0.0.1:6379> SETBIT sign 1 0     # 1 代表星期二  0 代表未打卡
(integer) 0
127.0.0.1:6379> SETBIT sign 2 0
(integer) 0
127.0.0.1:6379> SETBIT sign 3 1
(integer) 0
127.0.0.1:6379> SETBIT sign 4 1
(integer) 0
127.0.0.1:6379> SETBIT sign 5 0
(integer) 0
127.0.0.1:6379> SETBIT sign 6 0
(integer) 0

查询某一天是否有打卡!GETBIT

127.0.0.1:6379>  GETBIT sign 0        # 查看星期一是否打卡!输出1为已打卡
(integer) 1
127.0.0.1:6379>  GETBIT sign 1        # 查看星期二是否打卡!输出0为未打卡
(integer) 0

统计打卡次数!BITCOUNT

127.0.0.1:6379> BITCOUNT sign        # 统计打卡一个星期内的打卡次数
(integer) 3

事务

Redis事务本质:一组命令的集合!一个事务中的所有命令都会被序列化,在事务执行过程中,会按照顺序执行!

一次性,顺序性,排他性!执行一系列的命令

------ 队列  set  set  set  队列 ------

Redis事务没有隔离级别的概念!

所有的命令在事务中,并没有直接执行!只有发起执行命令的时候才会执行!Exec!!!

Redis单条命令是保证原子性的,但是事务是不保证原子性的!

redis的事务:

  • 开启事务(MULTI)
  • 命令入列(……)
  • 执行事务(EXEC)
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 v2
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) "v2"
4) OK

DISCARD:取消事务

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 v2
QUEUED
127.0.0.1:6379(TX)> set k4 v4
QUEUED
127.0.0.1:6379(TX)> DISCARD    # 取消事务
OK
127.0.0.1:6379> get k4    # 事务队列中的命令都不会被执行!
(nil)

编译型异常(代码有问题!命令有错误!),事务中所有的指令都不会被执行!

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 v2
QUEUED
127.0.0.1:6379(TX)> set k3 v3
QUEUED
127.0.0.1:6379(TX)> getset k3     # 错误的命令
(error) ERR wrong number of arguments for 'getset' command
127.0.0.1:6379(TX)> set k4 v4
QUEUED
127.0.0.1:6379(TX)> exec        # 执行事务报错!
(error) EXECABORT Transaction discarded because of previous errors.
127.0.0.1:6379> get k4    #所有的命令都不会被执行!
(nil)

运行时异常(1/0),如果事务队列中存在语法性,那么执行命令的时候,其他命令是可以正常执行的,错误命令抛出异常!

127.0.0.1:6379> set k1 "v1"
OK
127.0.0.1:6379> multi
OK
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)> set k3 v3
QUEUED
127.0.0.1:6379(TX)> get k3
QUEUED
127.0.0.1:6379(TX)> exec
1) (error) ERR value is not an integer or out of range        # 虽然第一条命令,但是依旧正常执行成功!
2) OK
3) OK
4) "v3"
127.0.0.1:6379> get k2
"v2"
127.0.0.1:6379> get k3
"v3"

WATCH:监控! watch加锁 unwatch解锁

悲观锁:

        很悲观,认为什么时候都会出问题,无论做什么都会加锁!

乐观锁:

        很乐观,认为什么时候都不会出问题,所以不会上锁!更新数据的时候去判断一下在此期间是否有人修改过数据。

        获取version

        更新的时候比较version

 Redis监控测试

# 正常执行成功
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    # 监视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    # 监视 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

# 执行之前,另外一个线程修改了money的值,这个时候就会导致事务执行失败!
127.0.0.1:6379(TX)> exec    
(nil)

如果修改失败,获取最新的值即可!

27.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)> DECRBY money 10
QUEUED
127.0.0.1:6379(TX)> INCRBY out 10
QUEUED

# 比对监视的值是否发生了变化,如果没有发生变化,那么可以执行成功,否则执行失败
127.0.0.1:6379(TX)> exec    
1) (integer) 990
2) (integer) 30
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值