概述
Redis是什么
Redis(Remote Dictionary Server ),即远程字典服务。
Redis是一个开源的使用ANSI C语言编写、遵守BSD协议、支持网络、可基于内存亦可持久化的日志型、Key-Value数据库,并提供多种语言的API。
它通常被称为数据结构服务器,因为值(value)可以是 字符串(String), 哈希(Hash), 列表(list), 集合(sets) 和 有序集合(sorted sets)等类型。
Redis能干什么?
1、内存存储、持久化(rdb,aof)
2、效率高,可以告诉缓存
3、发布订阅系统
4、地图信息分析
5、计时器、计数器
特性
1、支持多数据类型
2、持久化
3、集群
4、事物
性能
读的速度是110000次/s,写的速度是81000次/s 。
这里可以用是benchmark测试(菜鸟教程)
# 测试本机100个并发数,10万个请求
redis-benchmark -h localhost -p 6379 -c 100 -n 100000
基础知识
Redis中文网:http://www.redis.cn/
redis 默认是16个数据库
默认使用的是第0个数据库
127.0.0.1:6379> select 0 #切换数据库
OK
127.0.0.1:6379> dbsize #查看数据库大小
(integer) 4
查看数据库的所有键keys *
127.0.0.1:6379> keys *
1) "myset"
2) "counter:__rand_int__"
3) "myhash"
4) "key:__rand_int__"
127.0.0.1:6379>
清空当前数据库flushdb
127.0.0.1:6379> flushdb
OK
清空所有数据库flushall
127.0.0.1:6379> flushall
OK
为什么redis端口号是6379
因为redis作者喜欢的明星在9宫格是6379
mysql 3306 是女儿的名字。
Redis是单线程!
官方表示,Redis是基于内存操作,CPU不是Redis性能瓶颈,Redis的瓶颈时根据机器的内存和网络带宽,既然可以使用单线程来实现,就用单线程。
Redis是C语言写的,官方提供的数据为 10万+QPS,也就是不必Memecache性能差
Redis单线程为什么还这么快?
误区1:高性能的服务器一定是多线程的?
误区2:多线程一定比单线程效率高?(多线程CPU上下文切换!必然慢)
CPU>内存>硬盘 速度
核心:redis 是将所有数据放在内存中,所以单线程快。对于内存系统来说,没有上下文切换效率就是最高的。
五大数据类型
Redis is an open source (BSD licensed), in-memory data structure store, used as a database, cache, and message broker. Redis provides data structures such as strings, hashes, lists, sets, sorted sets with range queries, bitmaps, hyperloglogs, geospatial indexes, and streams. Redis has built-in replication, Lua scripting, LRU eviction, transactions, and different levels of on-disk persistence, and provides high availability via Redis Sentinel and automatic partitioning with Redis Cluster. Learn more →
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)。
Redis-Key
EXISTS key #查看是否存在key
move key dbNum #将key放到dbNum号库中
EXPIRE key 10 #设置key的过期时间为10s
ttl key #查看当前key的剩余时间
如果有不会的命令可以来中文网查询
String(字符串)
127.0.0.1:6379> set name zhangsan #设置值
OK
127.0.0.1:6379> keys * #查看所有键
1) "name"
127.0.0.1:6379> get name #根据键取值
"zhangsan"
127.0.0.1:6379> EXISTS name #查看键是否存在
(integer) 1
127.0.0.1:6379> APPEND name hello #追加字符串,如果不存在相当于set key
(integer) 13
127.0.0.1:6379> get name
"zhangsanhello"
127.0.0.1:6379>
1、自增 incr key
2、自减 decr key
3、按步长自增 INCRBY key len
4、按步长自增 DECRBY key len
5、按范围截取 GETRANGE key start end
127.0.0.1:6379> set aaa 123456
OK
127.0.0.1:6379> GETRANGE aaa 0 3
"1234"
127.0.0.1:6379> GETRANGE aaa 0 -1
"123446"
6、替换指定位置的字符串 SETRANGE key offset value
127.0.0.1:6379> get aaa
"123456"
127.0.0.1:6379> SETRANGE aaa 1 xx
(integer) 6
127.0.0.1:6379> get aaa
"1xx456"
7、设置过期时间 setex(set with expire)
127.0.0.1:6379> setex bbb 30 hello
OK
127.0.0.1:6379> ttl bbb
(integer) 27
8、如果不存在 设置 setnx(set if not exist)
分布式锁中常用
失败返回 0
127.0.0.1:6379> setnx bbb mangodb
(integer) 1
127.0.0.1:6379> setnx mydb mangodb
(integer) 1
127.0.0.1:6379> setnx bbb hadoop
(integer) 0
9、mset k1 v1 k2 v2 ...
一次设置多个值
127.0.0.1:6379> mset k1 v1 k2 v2 k3 v3
OK
127.0.0.1:6379> keys *
1) "k2"
2) "k3"
3) "k1"
127.0.0.1:6379> mget k1 k2 k3
1) "v1"
2) "v2"
3) "v3"
127.0.0.1:6379> msetnx k1 v1 k5 n5 ## 注意这里失败了 说明这个msetnx是原子性操作
(integer) 0
10、设置对象
127.0.0.1:6379> mset user:1:name zhangsan user:1:age 20
OK
127.0.0.1:6379> mget user:1:name user:1:age
1) "zhangsan"
2) "20"
#先get再set
127.0.0.1:6379> getset name zhangsan ##如果不存在 返回null 设置新值
(nil)
127.0.0.1:6379> get name
"zhangsan"
127.0.0.1:6379> getset name lisi ## 如果存在 返回当前值 然后用新值覆盖
"zhangsan"
127.0.0.1:6379> get name
"lisi"
【场景】:关注数量、粉丝数量增加等
List (列表)
1、插入与查询,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> 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>
2、根据下标查看值
#查看list中的值 根据下标
127.0.0.1:6379> lindex list 1
"two"
127.0.0.1:6379> lindex list 0
"three"
127.0.0.1:6379>
3、查看list的元素个数
127.0.0.1:6379> LLEN list
(integer) 4
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> RPOP list
"right"
#######移除指定值##########
取关 uid
这里移除的是指定个数的 value
127.0.0.1:6379> lrange list 0 -1
1) "two"
2) "two"
3) "two"
4) "one"
127.0.0.1:6379> LREM list 2 two #移除两个 two
(integer) 2
5、截取
127.0.0.1:6379> lrange list 0 -1
1) "four"
2) "two"
3) "three"
4) "one"
127.0.0.1:6379> ltrim list 0 1 #截取0-1的值
OK
127.0.0.1:6379> lrange list 0 -1
1) "four"
2) "two"
6、移除一个元素并且移动到指定list
127.0.0.1:6379> rpush list hello1
(integer) 1
127.0.0.1:6379> rpush list hell2
(integer) 2
127.0.0.1:6379> rpush list hello3
(integer) 3
127.0.0.1:6379> rpoplpush list mylist
"hello3"
127.0.0.1:6379> lrange mylist 0 -1
1) "hello3"
7、将列表指定下标值替换为别的值【注意】要求list必须存在
127.0.0.1:6379> lpush list v1
(integer) 1
127.0.0.1:6379> lrange list 0 -1
1) "v1"
127.0.0.1:6379> lset list 0 aaa
OK
127.0.0.1:6379> lrange list 0 -1
1) "aaa"
api实在太多了!只能用的时候看菜鸟教程了,我可真是个菜鸟
小结
- List实际上是一个链表,left 和right 都可以插入
- 如果key不存在,创建新链表
- 如果key存在,新增内容
- 如果移除了所有值,就代表链表不存在
- 在两边插入或改动值效率高
场景:队列,栈
Set(集合)
set中的值是无序不能重复的,下面是一组简单存取api
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> SMEMBERS myset #查看值
1) "hello"
2) "world"
127.0.0.1:6379> SISMEMBER myset hello #查看是否包含
(integer) 1
127.0.0.1:6379> SCARD myset #获取元素个数
(integer) 2
1、删除元素srem key remove value
127.0.0.1:6379> srem myset remove hello
(integer) 1
127.0.0.1:6379> SMEMBERS myset
1) "world"
2、随机抽取SRANDMEMBER
3、随机删除spop
127.0.0.1:6379> SMEMBERS myset
1) "wq"
2) "redis"
3) "hello"
4) "world"
127.0.0.1:6379> SRANDMEMBER myset
"hello"
127.0.0.1:6379> SRANDMEMBER myset
"hello"
127.0.0.1:6379> SRANDMEMBER myset
"redis"
127.0.0.1:6379> SRANDMEMBER myset
"wq"
127.0.0.1:6379> SRANDMEMBER myset
"wq"
127.0.0.1:6379> SRANDMEMBER myset
"redis"
127.0.0.1:6379> SRANDMEMBER myset
"hello"
127.0.0.1:6379> SRANDMEMBER myset
"world"
127.0.0.1:6379> SRANDMEMBER myset 2 #随机抽取指定个数元素
1) "hello"
2) "redis"
127.0.0.1:6379> spop myset #随机删除
"redis"
移动元素到其他集合smove key1 key2 value
127.0.0.1:6379> SMEMBERS myset
1) "redis"
2) "hello"
3) "world"
127.0.0.1:6379> SMEMBERS myset2
1) "hadoop"
2) "oracle"
3) "mysql"
127.0.0.1:6379> smove myset myset2 hello
(integer) 1
127.0.0.1:6379> SMEMBERS myset2
1) "hello"
2) "hadoop"
3) "oracle"
4) "mysql"
4、数字集合类
-差集
-交集
-并集
127.0.0.1:6379> SMEMBERS myset
1) "b"
2) "c"
3) "a"
127.0.0.1:6379> SMEMBERS myset2
1) "c"
2) "e"
3) "d"
##############
127.0.0.1:6379> SDIFF myset myset2 #差集
1) "b"
2) "a"
127.0.0.1:6379> SDIFF myset2 myset #差集
1) "d"
2) "e"
127.0.0.1:6379> SINTER myset myset2 #交集 共同好友
1) "c"
127.0.0.1:6379> SUNION myset myset2 #并集
1) "b"
2) "c"
3) "e"
4) "a"
5) "d"
微博,A用户将所有关注的人放在一个set中,将他的粉丝放在另一个set
共同关注,共同爱好,推荐好友,二度分割理论
Hash(哈希)
当成Map集合,key-Map
1、基本操作
添加hset key field1 value1 field2 value2…
127.0.0.1:6379> hset myhash field1 aaa
(integer) 1
127.0.0.1:6379> hget myhash field1
"aaa"
2、删除hdel key field
127.0.0.1:6379> hdel myhash field1
(integer) 1
3、获取长度hlen
4、获取所有值hgetall
127.0.0.1:6379> hset myhash field1 aaa field2 bbb filed3 ccc
(integer) 3
127.0.0.1:6379> hlen myhash
(integer) 3
127.0.0.1:6379> HGETALL myhash
1) "field1"
2) "aaa"
3) "field2"
4) "bbb"
5) "filed3"
6) "ccc"
5、判断是否存在hexists key field
127.0.0.1:6379> HEXISTS myhash field2
(integer) 1
6、只获得所有的field或者只获得所有的value
127.0.0.1:6379> hkeys myhash
1) "field1"
2) "field2"
3) "filed3"
127.0.0.1:6379> HVALS myhash
1) "aaa"
2) "bbb"
3) "ccc"
7、如果不存在则创建hsetnx key field value
场景:存储对象
String更适合字符串的存储
Zset(有序集合)
在set的基础上加了一个值,zset k1 scope1 v1
1、基本操作
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"
2、排序ZRANGEBYSCORE
127.0.0.1:6379> ZRANGEBYSCORE salary -inf +inf withscores
1) "zhangsan"
2) "500"
3) "lisi"
4) "2500"
5) "wangqwu"
6) "5000"
127.0.0.1:6379> ZREVRANGE salary 0 -1 withscores #从大到小
1) "wangqwu"
2) "5000"
3) "lisi"
4) "2500"
3、删除zrem
127.0.0.1:6379> zrem salary zhangsan
(integer) 1
127.0.0.1:6379> ZRANGE salary 0 -1 withscores
1) "lisi"
2) "2500"
3) "wangqwu"
4) "5000"
案例:排序,带权消息