概述
Redis是什么
Redis(Remote Dictionary Server ),即远程字典服务
是一个开源的使用ANSI C语言编写、支持网络、可基于内存亦可持久化的日志型、Key-Value数据库,并提供多种语言的API
redis会周期性的把更新的数据写入磁盘或者把修改操作写入追加的记录文件,并且在此基础上实现了master-slave(主从)同步。
免费和开源!是当下最热门的NoSQL技术之一!也被称为结构化数据库
Redis能干嘛
1.内存存储、持久化,内存中是断电既失、所以说持久化很重要(rdb、aof)
2.效率高、可用于高速缓存
3.发布订阅系统
4.地图信息分析
5.计时器。计数器
特性
1.多样的数据类型
2.持久化
3.集群
4.事务
学习要用的东西
redis官网 https://redis.io/
中文网 https://www.redis.net.cn/
测试性能
redis-benchmar压力测试工具 一些参数
100个并发 100000个请求
redis-benchmark -h localhost -p 6379 -c 100 -n 100000
基础知识
16个数据库
默认使用的是第0个
127.0.0.1:6379> select 3 #选择数据库
(error) NOAUTH Authentication required.
127.0.0.1:6379> auth "768355" #输入密码 赋权限
OK
127.0.0.1:6379> select 3
OK
127.0.0.1:6379[3]> DBSIZE #查询数据库大小
(integer) 0
127.0.0.1:6379> keys * #查询所有数据
1) "name"
FLUSHDB 清空当前数据库所有数据
FLUSHALL 清空所有数据库的数据
127.0.0.1:6379> FLUSHDB #清空当前数据库所有数据
OK
127.0.0.1:6379> keys *
(empty list or set)
redis是单线程的
官方表示redis是基于内存的操作,CPU不是Redis性能瓶颈,Redis的瓶颈是根据机器的内存和网络带宽,既然可以使用单线程来实现,就使用单线程了
Redis是C语言写的 100000+QPS 不比mamecache 差
Redis为什么单线程还那么快?
1.误区1:高性能的服务器一定是多线程的?
2.误区2:多线程(CPU上下文切换)一定比单线程效率高!
CPU >内存> 硬盘速度
核心:redis是将所有的数据全部放在内存中的,所以说使用单线程去操作效率就是最高的,多线程(CPU上下文切换:耗时的操作),
对于内存系统来说,如果没有上下文切换效率就是最高的!多次读写都是在一个CPU上的,在内存情况下,这个就是最佳方案。
五大数据类型
Redis是一个开源(BSD许可),内存存储的数据结构服务器,可用作数据库,高速缓存和消息队列代理。它支持字符串、哈希表、列表、集合、有序集合,位图,hyperloglogs等数据类型。内置复制、Lua脚本、LRU收回、事务以及不同级别磁盘持久化功能,同时通过Redis Sentinel提供高可用,通过Redis Cluster提供自动分区。
Redis-key
127.0.0.1:6379> keys * #查看所有的key
(empty list or set)
127.0.0.1:6379> set name cui #set key
OK
127.0.0.1:6379> keys *
1) "name"
127.0.0.1:6379> set age 2
OK
127.0.0.1:6379> keys *
1) "age"
2) "name"
127.0.0.1:6379> EXISTS name #判断当前key是否存在
(integer) 1
127.0.0.1:6379> EXISTS name1
(integer) 0
127.0.0.1:6379> move name 1 #移除当前key
(integer) 1
127.0.0.1:6379> keys *
1) "age"
127.0.0.1:6379> set name cui
OK
127.0.0.1:6379> set name cui
OK
127.0.0.1:6379> keys *
1) "age"
2) "name"
127.0.0.1:6379> get name
"cui"
127.0.0.1:6379> EXPIRE name 10 #过期时间
(integer) 1
127.0.0.1:6379> ttl name #查看当前剩余时间
(integer) 2
127.0.0.1:6379> ttl name
(integer) -2
127.0.0.1:6379> type name #查看当前key的类型
string
遇到不知道的命令去官网查询
String(字符串)
127.0.0.1:6379> set key1 v1 #设置值
OK
127.0.0.1:6379> get key1 #获取值
"v1"
127.0.0.1:6379> EXISTS key1 #判断key值是否存在
(integer) 1
127.0.0.1:6379> APPEND key1 "hello" #追加字符串,如果当前key不存在,相当于setkey
(integer) 7
127.0.0.1:6379> get key1
"v1hello"
127.0.0.1:6379> STRLEN key1 #获取字符串的长度
(integer) 7
127.0.0.1:6379> APPEND key1 "cui"
(integer) 10
127.0.0.1:6379> get key1
"v1hellocui"
##################################################################################
i++
i--
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
(integer) 1
127.0.0.1:6379> incr views
(integer) 2
127.0.0.1:6379> get views
"2"
127.0.0.1:6379> decr views #自减1
(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> INCRBY views 10 #自增10 可设置增长量
(integer) 9
127.0.0.1:6379> DECRBY views 5 #自减5
(integer) 4
########################################################3
#字符串范围rang
127.0.0.1:6379> set key1 "hello,cui" #设置key1的值
OK
127.0.0.1:6379> get key1
"hello,cui"
127.0.0.1:6379> GETRANGE key1 0 3 #截取字符串【0,3】
"hell"
127.0.0.1:6379> GETRANGE key1 0 -1 #截取全部字符串 和getkey一样
"hello,cui"
# 替换!
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 #替换指定位置开始的字符串
(integer) 7
127.0.0.1:6379> get key2
"axxdefg"
#############################################################################
# setex(set with expire) # 设置过期时间
# setnx(set if not exist)# 不存在在设置
127.0.0.1:6379> setex key3 30 "hello" #设置key3的值为hello,30秒后过期
OK
127.0.0.1:6379> ttl key3
(integer) 14
127.0.0.1:6379> ttl key3
(integer) -2
127.0.0.1:6379> get key3
(nil)
127.0.0.1:6379> setnx mykey "redis" #如果mykey不存在,创建mykey
(integer) 1
127.0.0.1:6379> keys *
1) "key1"
2) "mykey"
3) "key2"
127.0.0.1:6379> setnx mykey "MongoDB" #如果mykey存在,创建mykey失败
(integer) 0
127.0.0.1:6379> get mykey
"redis"
#############################################################
mset
mget
127.0.0.1:6379> mset k1 v2 k2 v2 k3 v3 #同时设置多个值
OK
127.0.0.1:6379> keys *
1) "k1"
2) "k3"
3) "k2"
127.0.0.1:6379> mget k1 k2 k3 #同时获取多个值
1) "v2"
2) "v2"
3) "v3"
127.0.0.1:6379> msetnx k1 v1 k4 v4 #msetnx是一个原子性的操作
(integer) 0
127.0.0.1:6379> get k4
(nil)
##########################################################
#对象
set user:1{name:zhangsan,age:3}#设置一个user:1 对象 值为json字符来保存一个对象
# 这里的key是一个巧妙的设计:user:{id}:{filed}
127.0.0.1:6379> mset user:1:name zhangsan user:1:age 2
OK
127.0.0.1:6379> mget user:1:name user:1:age
1) "zhangsan"
2) "2"
#############################################################
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"
Sring类似的使用场景:value除了是我们的字符串还可以是我们的数字
- 计数器
- 统计多单位的数量
- 粉丝数
- 对象缓存存储
List
基本的数据类型,列表
在redis里面,我们可以把list玩成,栈,队列,阻塞队列
所有的list的命令都是以L开头的
#########################################################3
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> LRANGE list 0 -1
1) "three"
2) "two"
3) "one"
4) "right"
#############################################################
LPOP
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> LRANGE list 0 -1
1) "two"
2) "one"
3) "right"
127.0.0.1:6379> RPOP list #移除list最后一个元素
"right"
127.0.0.1:6379> LRANGE list 0 -1
1) "two"
2) "one"
###############################################################
Lindex
127.0.0.1:6379> LINDEX list 1 #通过下标获得list中的某一个值
"one"
127.0.0.1:6379> LINDEX list 0
"two"
###############################################
Llen
127.0.0.1:6379> LRANGE list 0 -1
1) "two"
2) "one"
127.0.0.1:6379> LLEN list #返回列表长度
(integer) 2
#######################################################
127.0.0.1:6379> LRANGE list 0 -1
1) "two"
2) "two"
3) "one"
127.0.0.1:6379> LREM list 1 one #移除指定精确值
(integer) 1
127.0.0.1:6379> LRANGE list 0 -1
1) "two"
2) "two"
127.0.0.1:6379> LREM list 1 two
(integer) 1
127.0.0.1:6379> LRANGE list 0 -1
1) "two"
###################################################3
trim 修剪
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> LRANGE mylist 0 -1
1) "hello"
2) "hello1"
3) "hello2"
4) "hello3"
127.0.0.1:6379> LTRIM mylist 1 2 #通过下标截取指定长度,list改变只剩下截取的元素
OK
127.0.0.1:6379> LRANGE mylist 0 -1
1) "hello1"
2) "hello2"
##################################################################3
Rpoplpush #移除列表的最后一个元素,将他移动到新的列表中
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> RPOPLPUSH mylist myotherlist #移除列表的最后一个元素到新的列表中
"hello3"
127.0.0.1:6379> LRANGE mylist 0 -1 #查看原来列表
1) "hello"
2) "hello1"
3) "hello2"
127.0.0.1:6379> LRANGE myotherlist 0 -1 #查看新的列表
1) "hello3"
##########################################################33
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 item #如果不存在,则会报错
(error) ERR index out of range
######################################################################33
linsert #将某个具体的value插入到列表中某个元素的前面或者后面!
127.0.0.1:6379> RPUSH mylist "hello"
(integer) 1
127.0.0.1:6379> RPUSH mylist "world"
(integer) 2
127.0.0.1:6379> LINSERT mylist before "world" "other"
(integer) 3
127.0.0.1:6379> LRANGE list 0 -1
(empty list or set)
127.0.0.1:6379> LRANGE mylist 0 -1
1) "hello"
2) "other"
3) "world"
127.0.0.1:6379> LINSERT mylist after world now
(integer) 4
127.0.0.1:6379> LRANGE mylist 0 -1
1) "hello"
2) "other"
3) "world"
4) "now"
小结
- 他实际上是一个链表,before node after,left,right都可以插入值
- 如果key不存在,创建新的链表
- 如果key存在,新增内容
- 如果移除了所有值,空链表,也代表不存在
- 在两边插入或者改动值,效率最高!中间元素,相对来说效率会低一点
消息排队! 消息队列(Lpush Rpop),栈(Lpush Lpop)