Linux下Redis的安装步骤和基本数据类型的运用。
Linux下安装Redis
1、下载Linux版本的redis
2、将下载的redis放入到Linux中
3、解压redis
#一般我们将下载的源文件放在 /opt目录下
#解压命令
tar -zxvf redis-6.2.1.tar.gz
4、进入解压目录下
#1、安装gcc环境
redis-6.2.1.tar.gz
#2、查看gcc是否安装成功
gcc -v
#3、编译
make
4、编译安装
make install
redis默认安装在
/usr/local/bin
5、一般情况下我们会把redis.config
这个文件拷贝一份,到/usr/local/bin
下自己创建的一个文件夹中
#在`/usr/local/bin`目录下新建(myconfig)一个存放`redis.config`的文件夹
mkdir 文件夹名
#拷贝`redis.config`到自己创建的文件夹(myconfig是我自己创建的文件夹)中
cp /opt/redis-6.2.1/redis.conf /usr/local/bin/myconfig
6、启动redis
#进入 /usr/local/bin,启动redis服务
redis-server myconfig/redis.config
#启动redis客户端
redis-cli -p 6379
7、进行测试,设置一个key-value键值对
Redis性能测试
redis 性能测试的基本命令如下:
redis-benchmark [option] [option value]
redis 性能测试工具可选参数如下所示:
实例:
redis-benchmark -h localhost -p 6379 -c 100 -n 100000
Redis基本知识
ping #查看redis是否通
127.0.0.1:6379> ping
PONG
SHUTDOWN #关闭redis
exit #退出
DBSIZE #查看当前redis库的大小
127.0.0.1:6379> dbsize
(integer) 1
127.0.0.1:6379>
FLUSHDB #删除当前库的所有内容
FLUSHALL #删除所有库的所有数据
select [0-15] #选择redis库,redis一共默认存在16个库(0-15)
keys * #查看当前库下面的所有key值
Redis是使用单线程的,为什么使用单线程?为什么单线程这么快?
Redis五大基本数据类型
Redis-key的相关知识
官网介绍Redis:
Redis 是一个开源(BSD许可)的,内存中的数据结构存储系统,它可以用作数据库、缓存和消息中间件。 它支持多种类型的数据结构,如 字符串(strings), 散列(hashes), 列表(lists), 集合(sets), 有序集合(sorted sets) 与范围查询, bitmaps, hyperloglogs 和 地理空间(geospatial) 索引半径查询。 Redis 内置了 复制(replication),LUA脚本(Lua scripting), LRU驱动事件(LRU eviction),事务(transactions) 和不同级别的 磁盘持久化(persistence), 并通过 Redis哨兵(Sentinel)和自动 分区(Cluster)提供高可用性(high availability)。
127.0.0.1:6379> ping #查看redis是否连通
PONG
127.0.0.1:6379> get name #或者name 的值
"xieyong"
127.0.0.1:6379> keys * #查看所有的key
1) "name"
127.0.0.1:6379> set age 1 #设置age 的值
OK
127.0.0.1:6379> keys *
1) "name"
2) "age"
127.0.0.1:6379> exists name #判断是否存在name的key
(integer) 1
127.0.0.1:6379> exists abf
(integer) 0
127.0.0.1:6379> move name 1 #移除name ,1代表当前库,这个命令一般不用
(integer) 1
127.0.0.1:6379> keys *
1) "age"
127.0.0.1:6379> get age
"1"
127.0.0.1:6379> set name xieyong
OK
127.0.0.1:6379> keys *
1) "name"
2) "age"
127.0.0.1:6379> clear
127.0.0.1:6379> keys *
1) "name"
2) "age"
127.0.0.1:6379> get name
"xieyong"
127.0.0.1:6379> expire name 10 #设置key的过期时间,以秒为单位
(integer) 1
127.0.0.1:6379> ttl name #查看key的过期时间还剩多久
(integer) 4
127.0.0.1:6379> ttl name
(integer) 2
127.0.0.1:6379> ttl name
(integer) -2
127.0.0.1:6379> get name
(nil)
127.0.0.1:6379> get age
"1"
127.0.0.1:6379> EXPIRE age 3
(integer) 1
127.0.0.1:6379> ttl age
(integer) 0
127.0.0.1:6379> set name xieyong
OK
127.0.0.1:6379> type name #查看key的类型
string
127.0.0.1:6379> set age 1
OK
127.0.0.1:6379> type age
string
String类型
127.0.0.1:6379> flushALL
OK
127.0.0.1:6379> set key1 v1
OK
127.0.0.1:6379> get key1
"v1"
127.0.0.1:6379> keys *
1) "key1"
127.0.0.1:6379> EXISTS key1 #判断key1是否存在
(integer) 1
127.0.0.1:6379> APPEND key1 "hello" #在key1后追加字符串
(integer) 7
127.0.0.1:6379> get key1
"v1hello"
127.0.0.1:6379> get key1
"v1hello"
127.0.0.1:6379> APPEND key1 ",world"
(integer) 13
127.0.0.1:6379>
127.0.0.1:6379> get key1
"v1hello,world"
127.0.0.1:6379> substr key1 0 1 #截取字符串[0,1]
"v1"
127.0.0.1:6379> substr key1 1 4
"1hel"
127.0.0.1:6379> get key1
"v1hello,world"
127.0.0.1:6379> append name xieyong
(integer) 7
127.0.0.1:6379> keys *
1) "name"
2) "key1"
127.0.0.1:6379> strlen key1 #获取key1的长度
(integer) 13
127.0.0.1:6379> clear
127.0.0.1:6379> set views 1
OK
127.0.0.1:6379> incr views #自增+1
(integer) 2
127.0.0.1:6379> get views
"2"
127.0.0.1:6379> incr views
(integer) 3
127.0.0.1:6379> get views
"3"
127.0.0.1:6379> decr views #自减1
(integer) 2
127.0.0.1:6379> get views
"2"
127.0.0.1:6379> decr views
(integer) 1
127.0.0.1:6379> decr views
(integer) 0
127.0.0.1:6379> decr views
(integer) -1
127.0.0.1:6379> get views
"-1"
127.0.0.1:6379> incrby views 10 #自增10, views += 10;
(integer) 9
127.0.0.1:6379> get views
"9"
127.0.0.1:6379> decrby views 3 #自减3, views -= 3;
(integer) 6
127.0.0.1:6379> get views
"6"
127.0.0.1:6379> keys *
1) "name"
2) "views"
3) "key1"
#####################################################################
Range操作
127.0.0.1:6379> flushdb
OK
127.0.0.1:6379> keys *
(empty array)
127.0.0.1:6379> set key1 "hello,xieyong"
OK
127.0.0.1:6379> get key1
"hello,xieyong"
127.0.0.1:6379> getrange key1 0 3 #获取key1[0,3]
"hell"
127.0.0.1:6379> getrange key1 0 -1 #获取整个key1的值
"hello,xieyong"
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 #替换从1位置开始的值
(integer) 7
127.0.0.1:6379> get key2
"axxdefg"
#####################################################################
setex(set expire)
setnx(set if not exist)
127.0.0.1:6379> setex key3 30 "hello" #设置key3的值并且设置它的过期时间
OK
127.0.0.1:6379> ttl key3 #查看key3的过期时间
(integer) 24
127.0.0.1:6379> setnx mykey "redis" #如果mykey不存在就设置值会成功,否则就会失败
(integer) 1
127.0.0.1:6379> ttl key3
(integer) -2
127.0.0.1:6379> get mykey
"redis"
127.0.0.1:6379> setnx mykey "MongDB" #存在mykey这个键的值就不会设置成功,还是之前那个值
(integer) 0
127.0.0.1:6379> get mykey
"redis"
127.0.0.1:6379> keys *
1) "mykey"
2) "key2"
3) "key1"
#####################################################################
mset
mget
msetnx
127.0.0.1:6379> flushdb
OK
127.0.0.1:6379> keys *
(empty array)
127.0.0.1:6379> mset key1 v1 key2 v2 key3 v3 #mset设置多个键值对
OK
127.0.0.1:6379> keys *
1) "key2"
2) "key3"
3) "key1"
127.0.0.1:6379> mget key1 key2 key3 #获取多个键的值
1) "v1"
2) "v2"
3) "v3"
127.0.0.1:6379> mget key1 key2 key4
1) "v1"
2) "v2"
3) (nil)
127.0.0.1:6379> msetnx key1 v1 k4 v4 #如果设置的key不存在,则设置这些key的值
(integer) 0
127.0.0.1:6379> keys *
1) "key2"
2) "key3"
3) "key1"
127.0.0.1:6379> get k4
(nil)
127.0.0.1:6379> set user:1 {name:zhangsan,age:3} #存放一个对象
OK
127.0.0.1:6379> keys *
1) "user:1"
2) "key2"
3) "key3"
4) "key1"
127.0.0.1:6379> mset user:2:name lisi user:2:age 3 #这是redis比较好的玩法,很灵活
OK
127.0.0.1:6379> ,get user:1:name user:1:age
(error) ERR unknown command `,get`, with args beginning with: `user:1:name`, `user:1:age`,
127.0.0.1:6379> mget user:1:name user:1:age
1) (nil)
2) (nil)
127.0.0.1:6379> mget user:2:name user:2:age
1) "lisi"
2) "3"
127.0.0.1:6379> getset db redis #先获得再设置
(nil)
127.0.0.1:6379> get db
"redis"
127.0.0.1:6379> getset db MongDB
"redis"
127.0.0.1:6379> get db
"MongDB"
127.0.0.1:6379> incr nid:342:follow
(integer) 1
127.0.0.1:6379> get nid:342:follow
"1"
String运用场景
String类似的使用场景:value除了是我们的字符串还可以是我们的数字!
-
计数器
-
统计多单位的数量
-
粉丝数
-
对象缓存存储!
-
incr可以用户阅读量的增长,粉丝的增长,关注量的增长等等
List(链表)
#####################################################################
lpush,lpop,rpush,rpop #list的push和pop可以在list的左右两边操作
127.0.0.1:6379> lpush list one #在list中新增值
(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> lrange list 0 -1
1) "three"
2) "two"
3) "one"
4) "right"
127.0.0.1:6379> lpop list
"three"
127.0.0.1:6379> lrange list 0 -1
1) "two"
2) "one"
3) "right"
127.0.0.1:6379> rpop list
"right"
127.0.0.1:6379> lrange list 0 -1
1) "two"
2) "one"
127.0.0.1:6379> rpop list 2
1) "one"
2) "two"
127.0.0.1:6379> lrange list 0 -1
(empty array)
127.0.0.1:6379> lpush list 0
(integer) 1
127.0.0.1:6379> lpush list 1
(integer) 2
127.0.0.1:6379> lpush list 2
(integer) 3
127.0.0.1:6379> lrange list 0 -1
1) "2"
2) "1"
3) "0"
#####################################################################
lindex #获取list中固定位置的值
127.0.0.1:6379> lindex list 0 #获取list中第0个位置的值,前提是list存在值,不存在就会报错,拿不到
"2"
127.0.0.1:6379> lindex list 1
"1"
127.0.0.1:6379> lindex list 3
(nil)
127.0.0.1:6379> lindex list 2
"0"
127.0.0.1:6379> llen list #获取list的长度,前提list存在
(integer) 3
127.0.0.1:6379> expire list 20 #设置list的过期时间,以秒s为单位
(integer) 1
127.0.0.1:6379> ttl list
(integer) 16
127.0.0.1:6379> ttl list
127.0.0.1:6379> ttl list
(integer) -2
127.0.0.1:6379> lrange list 0 -1
(empty array)
127.0.0.1:6379> lpush list 0
(integer) 1
127.0.0.1:6379> lpush list 1
(integer) 2
127.0.0.1:6379> lpush list 2
(integer) 3
127.0.0.1:6379> lpush list 2
(integer) 4
127.0.0.1:6379> lrange list 0 -1
1) "2"
2) "2"
3) "1"
4) "0"
#####################################################################
lrem key count value #移除list中value的个数
127.0.0.1:6379> lrem list 1 1 #移除一个list中为1的值,从list的最左边开始移除
(integer) 1
127.0.0.1:6379> lrange list 0 -1
1) "2"
2) "2"
3) "0"
127.0.0.1:6379> lrem list 2 2 #移除两个list中为2的值
(integer) 2
127.0.0.1:6379> lrange list 0 -1
1) "0"
127.0.0.1:6379> lpush list one
(integer) 2
127.0.0.1:6379> lpush list two
(integer) 3
127.0.0.1:6379> lpush list three
(integer) 4
127.0.0.1:6379> lrange list 0 -1
1) "three"
2) "two"
3) "one"
4) "0"
127.0.0.1:6379> rpush mylist "hello"
(integer) 1
127.0.0.1:6379> rpush mylist "hello1"
(integer) 2
127.0.0.1:6379> rpush mylist "hello2"
(integer) 3
127.0.0.1:6379> rpush mylist "hello3"
(integer) 4
127.0.0.1:6379> ltrim mylist 1 2 #截取list中指定区间[1,2]的值,
OK
127.0.0.1:6379> lrange mylist 0 -1
1) "hello1"
2) "hello2"
#####################################################################
rpoplpush #移除list中最左边的值push到一个新的list中
127.0.0.1:6379> flushdb
OK
127.0.0.1:6379> rpush mylist "hello"
(integer) 1
127.0.0.1:6379> rpush mylist "hello1"
(integer) 2
127.0.0.1:6379> rpush mylist "hello2"
(integer) 3
127.0.0.1:6379> rpoplpush mylist otherlist #移除list中最左边的值push到一个新的list中
"hello2"
127.0.0.1:6379> lrange mylist 0 -1
1) "hello"
2) "hello1"
127.0.0.1:6379> lrange otherlist 0 -1
1) "hello2"
#####################################################################
lset #更新list指定位置的值
127.0.0.1:6379> flushdb
OK
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 #更新list中0位置的值,前提list中0位置有值
OK
127.0.0.1:6379> lrange list 0 0
1) "item"
127.0.0.1:6379> lset list 1 v1
(error) ERR index out of range
127.0.0.1:6379>
127.0.0.1:6379> exists list
(integer) 1
#####################################################################
linsert #在list的指定值之前或者之后插入一个元素
127.0.0.1:6379> flushdb
OK
127.0.0.1:6379> rpush mulist hello
(integer) 1
127.0.0.1:6379> rpush mulist world
(integer) 2
127.0.0.1:6379> linsert mylist before world other #在list中最左边的world之前新增一个other的值
(integer) 0
127.0.0.1:6379> lrange mylist 0 -1
(empty array)
127.0.0.1:6379> linsert mulist before world other
(integer) 3
127.0.0.1:6379> lrange mulist 0 -1
1) "hello"
2) "other"
3) "world"
127.0.0.1:6379> linsert mulist after world new #在list中最左边的world之后新增一个new的值
(integer) 4
127.0.0.1:6379> lrange mulist 0 -1
1) "hello"
2) "other"
3) "world"
4) "new"
List总结
- 可以用作消息队列,因为list可以从它的左右两边都push和pop值
- 可以用作栈(lpush,lpop)
- 在两边插入或者改动值,效率最高! 中间元素,相对来说效率会低一点
- 如果key 不存在,创建新的链表,如果key存在,新增内容
- 如果移除了所有值,空链表,也代表不存在
Set(集合)
#####################################################################
set集合的基本操作,新增、删除、查看集合
127.0.0.1:6379> sadd myset hello #在set集合中新增一个元素
(integer) 1
127.0.0.1:6379> sadd myset xieyong
(integer) 1
127.0.0.1:6379> sadd myset love
(integer) 1
127.0.0.1:6379> smembers myset #查看set集合中的所有元素
1) "xieyong"
2) "love"
3) "hello"
#####################################################################
SCARD、SREM
127.0.0.1:6379> SISMEMBER myset hello #判断这个元素是否存在于set集合中
(integer) 1
127.0.0.1:6379> SISMEMBER myset world
(integer) 0
127.0.0.1:6379> SCARD myset #查看set集合中的元素总数
(integer) 3
127.0.0.1:6379> SREM myset hello #移除set集合中某个指定的元素
(integer) 1
127.0.0.1:6379> scard myset #查看set集合中的元素总数
(integer) 2
127.0.0.1:6379> SMEMBERS myset #查看set集合中的所有元素
1) "xieyong"
2) "love"
127.0.0.1:6379> sadd myset hello,redis #set集合新增一个元素
(integer) 1
127.0.0.1:6379> SMEMBERS myset #查看set集合中所有的元素
1) "xieyong"
2) "hello,redis"
3) "love"
#####################################################################
SRANDMEMBER、spop
127.0.0.1:6379> SRANDMEMBER myset #随机抽取set中的一个元素
"xieyong"
127.0.0.1:6379> SRANDMEMBER myset
"love"
127.0.0.1:6379> SRANDMEMBER myset
"love"
127.0.0.1:6379> SRANDMEMBER myset
"love"
127.0.0.1:6379> SRANDMEMBER myset
"xieyong"
127.0.0.1:6379> SRANDMEMBER myset
"xieyong"
127.0.0.1:6379> SRANDMEMBER myset
"xieyong"
127.0.0.1:6379> SRANDMEMBER myset 2 #随机抽取set集合中的两个元素,元素个数可以根据需求随便指定
1) "xieyong"
2) "hello,redis"
127.0.0.1:6379> SRANDMEMBER myset 2
1) "xieyong"
2) "love"
127.0.0.1:6379> smembers myset
1) "xieyong"
2) "hello,redis"
3) "love"
127.0.0.1:6379> spop myset #随机删除并获取set集合中的元素
"love"
127.0.0.1:6379> spop myset
"hello,redis"
#####################################################################
smove
127.0.0.1:6379> flushdb
OK
127.0.0.1:6379> sadd myset hello
(integer) 1
127.0.0.1:6379> sadd myset world
(integer) 1
127.0.0.1:6379> sadd myset xieyong
(integer) 1
127.0.0.1:6379> sadd myset2 set2
(integer) 1
127.0.0.1:6379> smove myset myset2 xieyong #将一个set集合中指定的值移到另一个set集合去
(integer) 1
127.0.0.1:6379> SMEMBERS myset
1) "world"
2) "hello"
127.0.0.1:6379> SMEMBERS myset2
1) "xieyong"
2) "set2"
#####################################################################
- 差集
- 交集
- 并集
127.0.0.1:6379> FLUSHDB
OK
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 #求两个set集合的差集
1) "a"
2) "b"
127.0.0.1:6379> SINTER key1 key2 #求两个集合的交集
1) "c"
127.0.0.1:6379> SUNION key1 key2 #求两个集合的并集
1) "e"
2) "b"
3) "c"
4) "a"
5) "d"
Set集合的运用场景
- Set集合中的元素是不可以重复的,跟Java中的Set集合一样
- 将用户的关注放在一个set集合中,将粉丝放在一个集合中
- 微博或者b站等的共同关注、共同爱好,利用SDIFF、SINTER、SUNION求差集、交集、并集
- 社交软件的好友推荐
Hash (散列)
hash类型和String类型非常的相似,hash类型为key-map类型模式
#####################################################################
127.0.0.1:6379> HSET myhash field1 xy #在hash集合中新增一个元素
(integer) 1
127.0.0.1:6379> hget myhash field1 #hash集合获取一个元素
"xy"
127.0.0.1:6379> hmset myhash field1 hello f2 world #hash集合中新增多个元素
OK
127.0.0.1:6379> hmget field1 f2
1) (nil)
127.0.0.1:6379> hmget myhash field1 f2 #hash集合中获取多个元素
1) "hello"
2) "world"
127.0.0.1:6379> HGETALL myhash #hash集合中获取所有的元素,查到的是键值对呈现
1) "field1"
2) "hello"
3) "f2"
4) "world"
127.0.0.1:6379> HDEL myhash f2 #删除hash集合中的一个元素
(integer) 1
127.0.0.1:6379> HGETALL myhash
1) "field1"
2) "hello"
#####################################################################
127.0.0.1:6379> hlen myhash #获取hash集合的长度
(integer) 1
127.0.0.1:6379> hmset myhash f2 world f3 redis #hash集合设置多个元素
OK
127.0.0.1:6379> hlen myhash
(integer) 3
127.0.0.1:6379> HEXISTS myhash f2 #判断hash集合是否存在某个元素
(integer) 1
#####################################################################
127.0.0.1:6379> HKEYS myhash #获取hash集合中所有的键
1) "field1"
2) "f2"
3) "f3"
127.0.0.1:6379> HVALS myhash #获取hash集合中所有的值
1) "hello"
2) "world"
3) "redis"
#####################################################################
127.0.0.1:6379> hset myhash f4 5
(integer) 1
127.0.0.1:6379> HINCRBY myhash f4 1 #元素自增
(integer) 6
127.0.0.1:6379> HSETNX myhash f2 w #如果hash集合中存在这个键的话就不新增,不存在的话就新增这个元素
(integer) 0
127.0.0.1:6379> HGETALL myhash
1) "field1"
2) "hello"
3) "f2"
4) "world"
5) "f3"
6) "redis"
7) "f4"
8) "6"
127.0.0.1:6379> hset user:1 name lisi age 3 #在hash集合中新增一个对象元素
(integer) 2
127.0.0.1:6379> hget user:1 name
"lisi"
127.0.0.1:6379> hget user:1 age
"3"
Hash类型的运用场景
- 适合做用户的信息的存储、变更
Zset(有序集合)
Zset和Set的操作基本类似,只是Zset它是属于有序的。
127.0.0.1:6379> ZADD myset 1 one # 有序几个新增一个元素
(integer) 1
127.0.0.1:6379> ZADD myset 2 two 3 three #新增多个元素
(integer) 2
127.0.0.1:6379> zrange myset 0 -1 #查看有序集合的全部元素
1) "one"
2) "two"
3) "three"
127.0.0.1:6379> zadd salary 2500 user1
(integer) 1
127.0.0.1:6379> zadd salary 5000 user2
(integer) 1
127.0.0.1:6379> zadd salary 500 user3
(integer) 1
#####################################################################
#ZRANGEBYSCORE key min max [WITHSCORES] [LIMIT offset count]
127.0.0.1:6379> ZRANGEBYSCORE salary -inf +inf #顺序排序,获取集合中所有的值
1) "user3"
2) "user1"
3) "user2"
127.0.0.1:6379> ZRANGE salary 0 -1 #顺序获取所有的值
1) "user3"
2) "user1"
3) "user2"
127.0.0.1:6379> ZRANGEBYSCORE salary -inf +inf withscores#顺序获取所有的值以及值的权重值
1) "user3"
2) "500"
3) "user1"
4) "2500"
5) "user2"
6) "5000"
127.0.0.1:6379> ZRANGEBYSCORE salary -inf +2500 withscores #获取[-inf,+2500]区间内的值和值权重
1) "user3"
2) "500"
3) "user1"
4) "2500"
127.0.0.1:6379> ZRANGEBYSCORE salary 600 +2500 withscores
1) "user1"
2) "2500"
127.0.0.1:6379> zrange salary 0 -1
1) "user3"
2) "user1"
3) "user2"
#####################################################################
zrem 移除元素
127.0.0.1:6379> zrem salary user1 #移除集合中的值
(integer) 1
127.0.0.1:6379> zrange salary 0 -1
1) "user3"
2) "user2"
#####################################################################
ZCARD 返回key的有序集元素个数
127.0.0.1:6379> ZCARD salary #返回key的有序集元素个数。
(integer) 2
127.0.0.1:6379> ZREVRANGE salary 0 -1 #倒叙获取集合中所有的值
1) "user2"
2) "user3"
127.0.0.1:6379> ZRANGE salary 0 -1
1) "user3"
2) "user2"
#####################################################################
zcount 统计区间内的数量
127.0.0.1:6379> zcount salary 100 5000 #统计区间内的数量
(integer) 2
127.0.0.1:6379> zadd myset 1 hello 2 world 3 abc
(integer) 3
127.0.0.1:6379> zcount myset 1 3
(integer) 6
127.0.0.1:6379> zrange myset 0 -1
1) "hello"
2) "one"
3) "two"
4) "world"
5) "abc"
6) "three"
127.0.0.1:6379> zcount myset 1 2
(integer) 4
127.0.0.1:6379>
127.0.0.1:6379> keys *
1) "salary"
2) "myset"
127.0.0.1:6379> ZRANGE myset 0 -1 withscores #获取集合中所有的值及score
1) "hello"
2) "1"
3) "one"
4) "1"
5) "two"
6) "2"
7) "world"
8) "2"
9) "abc"
10) "3"
11) "three"
12) "3"
Zset运用场景
- 成绩排序
- 排行榜
- 有关权重的问题
三种特殊数据类型
Geospatail (地理位置)
geoadd 将给定的空间元素(纬度、经度、名字)添加到指定的键里面
#有效的经度介于 -180 度至 180 度之间。
#有效的纬度介于 -85.05112878 度至 85.05112878 度之间。
127.0.0.1:6379> GEOADD china:city 116.40 39.90 beijing #添加一个元素
(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.50 29.53 chongqing 114.08 22.54 shenzhen
(integer) 2
127.0.0.1:6379> GEOADD china:city 120.16 30.24 hangzhou 108.96 34.26 xian
(integer) 2
geopos
127.0.0.1:6379> GEOPOS china:city beijing #获取地图中指定地方的经纬度
1) 1) "116.39999896287918091"
2) "39.90000009167092543"
127.0.0.1:6379> GEOPOS china:city beijing shanghai #获取地图中多个地方的经纬度
1) 1) "116.39999896287918091"
2) "39.90000009167092543"
2) 1) "121.47000163793563843"
2) "31.22999903975783553"
geodist
单位:
m 表示单位为米。
km 表示单位为千米。
mi 表示单位为英里。
ft 表示单位为英尺。
127.0.0.1:6379> GEODIST china:city beijing shanghai #获取两地之间的距离,前提是在这里集合中存在这个地方
"1067378.7564"
127.0.0.1:6379> GEODIST china:city beijing shanghai km #获取两地之间的距离,单位km
"1067.3788"
127.0.0.1:6379> geodist china:city shanghai hangzhou
"166761.2770"
127.0.0.1:6379> GEODIST china:city beijing chongqing
"1464070.8051"
127.0.0.1:6379> GEODIST china:city beijing chongqing km
"1464.0708"
127.0.0.1:6379> geodist china:city shanghai hangzhou km
"166.7613"
georadius
127.0.0.1:6379> GEORADIUS china:city 110 30 1000 km #获取以这个经纬度为圆心,半径为1000km的城市名,前提是这个城市在这个地图集合中
1) "chongqing"
2) "xian"
3) "shenzhen"
4) "hangzhou"
127.0.0.1:6379> GEORADIUS china:city 110 30 1000 km withcoord #获取以这个经纬度为圆心,半径为1000km的城市名和这些城市的经纬度
1) 1) "chongqing"
2) 1) "106.49999767541885376"
2) "29.52999957900659211"
2) 1) "xian"
2) 1) "108.96000176668167114"
2) "34.25999964418929977"
3) 1) "shenzhen"
2) 1) "114.08000081777572632"
2) "22.53999903789756587"
4) 1) "hangzhou"
2) 1) "120.1600000262260437"
2) "30.2400003229490224"
127.0.0.1:6379> GEORADIUS china:city 110 30 500 km withcoord
1) 1) "chongqing"
2) 1) "106.49999767541885376"
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 #获取以这个经纬度为圆心,半径为500km的城市名及元圆心到这个城市的距离
1) 1) "chongqing"
2) "341.9374"
2) 1) "xian"
2) "483.8340"
127.0.0.1:6379> GEORADIUS china:city 110 30 1000 km count 3 #获取三个以这个经纬度为圆心,半径为1000km的城市名
1) "chongqing"
2) "xian"
3) "shenzhen"
127.0.0.1:6379> GEORADIUS china:city 110 30 1000 km
1) "chongqing"
2) "xian"
3) "shenzhen"
4) "hangzhou"
geiradiusbymember
127.0.0.1:6379> GEORADIUSBYMEMBER china:city beijing 1000 km #获取以这个城市圆心,半径为1000km内的所有城市
1) "beijing"
2) "xian"
127.0.0.1:6379> GEORADIUSBYMEMBER china:city shanghai 500 km
1) "hangzhou"
2) "shanghai"
GEOHASH
127.0.0.1:6379> GEOHASH china:city beijing shanghai #该命令将返回11个字符的Geohash字符串
1) "wx4fbxxfke0"
2) "wtw3sj5zbj0"
geospatail的底层实现原理其实就是Zset
127.0.0.1:6379> ZREM china:city chongqing #移除一个元素
(integer) 1
127.0.0.1:6379> zrange china:city 0 -1 #返回地图集合中所有的元素
1) "chongqing"
2) "xian"
3) "shenzhen"
geospatail的运用场景
- 微信附近的人的实现
- 微信好友的定位
- 打车距离计算
HyperLogLogs
HyperLogLog是一种概率数据结构,用于对唯一事物进行计数(从技术上讲,这是指估计集合的基数)。通常,对唯一项目进行计数需要使用与要计数的项目数量成比例的内存量,因为您需要记住过去已经看到的元素,以避免多次对其进行计数。但是,有一组算法会以内存换取精度:在Redis实现的情况下,您得出的带有标准误差的估计度量最终会小于1%。该算法的神奇之处在于,您不再需要使用与所计数项目数成正比的内存量,而是可以使用恒定数量的内存!在最坏的情况下为12k字节。
127.0.0.1:6379> PFADD mykey a c s f w q a f r g #新增多个元素
(integer) 1
127.0.0.1:6379> PFCOUNT mykey #统计集合中不重复元素的个数
(integer) 8
127.0.0.1:6379> PFADD mykey2 s d a e f q a g x g
(integer) 1
127.0.0.1:6379> PFCOUNT mykey mykey2 #统计两个集合的并集的个数
(integer) 11
127.0.0.1:6379> PFCOUNT mykey2
(integer) 8
127.0.0.1:6379> PFMERGE mykey3 mykey mykey2 #统计两个集合的并集的个数,然后将并集存到mykey3中
OK
127.0.0.1:6379> PFCOUNT mykey2
(integer) 8
127.0.0.1:6379> PFCOUNT mykey3
(integer) 11
HyperLogLogs的运用场景
- 统计UV 【独立访问者数量(unique visitors)】
以前传统的方法统计:通过set,这样会浪费很多的空间。但是不会出错,HyperLogLogs有一定的误差。
(传统的方式, set 保存用户的id,然后就可以统计 set 中的元素数量作为标准判断 !
这个方式如果保存大量的用户id,就会比较麻烦!我们的目的是为了计数,而不是保存用户id;)
Bitmap
位图不是实际的数据类型,而是在String类型上定义的一组面向位的操作。由于字符串是二进制安全Blob,并且其最大长度为512 MB,因此它们适合设置多达2 ^ 32个不同的位。
位操作分为两组:固定时间的单个位操作(如将一个位设置为1或0或获取其值),以及对位组的操作,例如计算给定位范围内设置的位的数量(例如,人口计数)。
位图的最大优点之一是,在存储信息时,它们通常可以节省大量空间。例如,在以增量用户ID表示不同用户的系统中,仅使用512 MB内存就可以记住40亿用户的一位信息(例如,知道用户是否要接收新闻通讯)。
127.0.0.1:6379> setbit sign:xiaohong 0 1
(integer) 0
127.0.0.1:6379> setbit sign:xiaohong 1 0
(integer) 1
127.0.0.1:6379> setbit sign:xiaohong 2 1
(integer) 0
127.0.0.1:6379> setbit sign:xiaohong 3 1
(integer) 0
127.0.0.1:6379> setbit sign:xiaohong 4 0
(integer) 0
127.0.0.1:6379> setbit sign:xiaohong 5 1
(integer) 0
127.0.0.1:6379> getbit sign:xiaohong 5
(integer) 1
127.0.0.1:6379> BITCOUNT sign:xiaohong
(integer) 4
127.0.0.1:6379> getbit sign:xiaohong 0
(integer) 1
127.0.0.1:6379> getbit sign:xiaohong 1
(integer) 0
Bitmap运用场景
- 只存在两个状态的场景都可以使用
- 365天打卡等
事务
MULTI 、 EXEC 、 DISCARD 和 WATCH 是 Redis 事务相关的命令。事务可以一次执行多个命令, 并且带有以下两个重要的保证:
事务是一个单独的隔离操作:事务中的所有命令都会序列化、按顺序地执行。事务在执行的过程中,不会被其他客户端发送来的命令请求所打断。
事务是一个原子操作:事务中的命令要么全部被执行,要么全部都不执行。
EXEC 命令负责触发并执行事务中的所有命令:
如果客户端在使用 MULTI 开启了一个事务之后,却因为断线而没有成功执行 EXEC ,那么事务中的所有命令都不会被执行。
另一方面,如果客户端成功在开启事务之后执行 EXEC ,那么事务中的所有命令都会被执行。
Redis 事务本质:一组命令的集合! 一个事务中的所有命令都会被序列化,在事务执行过程的中,会按
照顺序执行!
一次性、顺序性、排他性!执行一些列的命令!
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
放弃事务
127.0.0.1:6379> MULTI #开启事务
OK
#命令入队
127.0.0.1:6379(TX)> set k4 v4
QUEUED
127.0.0.1:6379(TX)> set k5 v5
QUEUED
127.0.0.1:6379(TX)> DISCARD #放弃事务,事务放弃之后队列中所有的命令将不会被执行
OK
127.0.0.1:6379> keys * #观察的到,还是之前库中的数据,放弃的事务中的命令没有被执行
1) "k2"
2) "k3"
3) "k1"
127.0.0.1:6379> get k4
(nil)
编译型异常(代码有问题! 命令有错!) ,事务中所有的命令都不会被执行!
127.0.0.1:6379> MULTI #开启事务
OK
#命令入队
127.0.0.1:6379(TX)> set k4 v4
QUEUED
127.0.0.1:6379(TX)> ser k5 v5 #错误命令
(error) ERR unknown command `ser`, with args beginning with: `k5`, `v5`, #错误命令报错
127.0.0.1:6379(TX)> EXEC #执行事务,报错。整个事务将不会被执行
(error) EXECABORT Transaction discarded because of previous errors.
运行时异常(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 #对字符串加1,这是错误命令
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"
Watch 监视、监控
悲观锁:
- 任何时候都会加锁
乐观锁:
-
跟新数据的时候去判断一下,在此期间是否有人修改过这个数据
-
获取version
-
更新的时候比较versoin
#单线程下执行
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的乐观锁操作
#线程1
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
127.0.0.1:6379(TX)> EXEC #执行之前有线程2修改了money的值,这个时候会导致事务执行失败
(nil)
#线程2
127.0.0.1:6379> get money
"80"
127.0.0.1:6379> set money 100 #在线程1事务还未执行的时候更改money的值
OK
127.0.0.1:6379> get money
"100"
如果事务执行失败,先用unwatch解锁
127.0.0.1:6379> UNWATCH #对之前加锁的对象(money)解锁
OK
127.0.0.1:6379> WATCH money #重新加锁,获取监控对象最新的值,相当于mysql中的select version
OK
127.0.0.1:6379> get money #可以看到,得到的是最新的值
"100"
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) 90
2) (integer) 30