redis使用详细的教程
- 一、Nosql概述
-
- 1.数据库发展史
-
- 1)单机mysql的年代
- 2)Memcached(分布式高速缓存系统) mysql 垂直拆分(读写分离)
- 3)分库分表 水平拆分 MySQL集群
- 4)最近的年代
- 2.为什么要用?nosql?
- 3.什么是nosql?
- 4.nosql特点是什么?
- 5.nosql的四大分类
- 二、redis入门
-
- 1.什么是redis?
- 2.redis能干什么?
- 3.特性
- 4.学习中需要用到的东西
- 5.安装
- 6.性能测试
- 7.基础知识
-
- 基本命令
- Redis 是单线程的
- 三、redis五大数据类型
-
- 1.String 字符串
-
- 1.1 判断是否存在追加,获得长度
- 1.2 字符串类型为整数增减
- 1.3 截取和替换
- 1.4 设置时间
- 1.5 多个值的set 和获取get以及对象存储
- 1.6 先获取后设置
- 应用场景
- 2.List
- 3.Set
- 4.Hash
- 5.Zset(有序集合)
- 四、三种特殊数据类型
-
- 1.Geospatal 地理位置
-
- 1.1 geoadd 添加地理位置
- 1.2 geopos 获取地理位置定位
- 1.3 geodist 计算两个人之间的距离
- 1.4 georadius 以经纬度为中心,在半径内找到元素
- 1.5 georadiusbymember:以元素为中心,搜索半径内的元素
- 1.6 geohash:以字符串表示返回的经纬度
- 2.Hyperloglog 计数
- 3.Bitmap 位存储
- 五、事务
- 六、Jedis连接工具和SpringBoot整合Redis
-
- 1.Jedis连接工具
- 2.SpringBoot整合Redis
- 七、持久化
-
- 1.RDB
-
- 1.1 什么是RDB?
- 2.AOF
- 八、订阅发布
- 九、主从复制
- 十、哨兵模式
- 十一、缓存穿透和雪崩
一、Nosql概述
1.数据库发展史
1)单机mysql的年代
在20世纪90年代,一个基本的网站通常没有太多的访问,单个数据库就足够了 当时静态网站用的比较多。 那么,整个应用系统的瓶颈是什么呢?
- 数据量太大,机器无法安装(数据库保存数据是一个持久的操作,需要保存在硬盘上)
- 数据索引问题,如果一张表有数百万的数据,肯定需要索引,但索引太多,机器不能安装
- 服务器无法承受访问量(读写) 只要上述问题开始出现,就必须升级。
2)Memcached(分布式高速缓存系统) mysql 垂直拆分(读写分离)
memcached这是一种缓存技术,它可以将您的数据放入内存中,从而通过内存访问加速,因为内存是最快的,缓存技术的主要目的是加速!
在memcached保养了一个大的hashtable在内存中,表的结构是key和value memcached的key一般是字串,不能重复 memcached的value(字符串、数值、数组、对象、布尔、二进制数据、图片和视频)
80%的网站都在阅读。每次直接查询数据库都很麻烦,数据库无法携带。因此,我们希望减轻数据库的压力,并使用缓存来确保效率! 这个时代的发展过程:优化数据库结构和索引(优化数据库底层)–> 文件缓存(IO,在文件中保存数据肯定比数据库好) --> Memcached(当时最流行的技术)
针对单机mysql,为了解决高并发解决高并发阅读的压力cache缓存可以很好地解决这个问题。 数据库可以垂直拆分,比如一个读两个写。写作内容通过主从复制同步更新到另外两个数据库。
3)分库分表 水平拆分 MySQL集群
随着技术和业务的不断发展,对性能的要求越来越高 本质:数据库(读写) 早些年MyISAM:表锁对效率影响很大!高并发会导致严重的锁问题 转战Innodb:行锁 慢慢开始用分库分表来解决写作压力! mysql集群满足了当年的需求
4)最近的时代
mysql关系数据库不够,因为数据量大,变化快 Mysql有些人用他来存储一些更大的文件、博客、图片!如果有一个数据库来处理这些数据,如果数据库很大,效率很低,mysql压力变得很小。(研究如何处理这些问题)
2.为什么要用?nosql?
个人信息、社交网络、地理位置、用户自身数据、用户日志等爆炸性增长。 我们需要在这个时候使用它Nosql解决这些问题的数据库
3.什么是nosql?
nosql = not only sql 不仅仅是sql,一般指非关系数据库web2.随着互联网的诞生,传统的关系数据库很难处理2.0时代,特别是超大规模高并发社区, 暴露了很多问题,所以nosql在今天的大数据库下发展迅速。
用户的个人信息、社交网络和地理位置。这些数据类型的存储不需要固定格式!水平扩展不需要额外的操作!
4.nosql特点是什么?
- 方便扩展(数据之间没有关系,很好扩展)
- 高性能的大数据量(redis每秒可写8万次,读11万次,nosql缓存记录级,是细粒度缓存,性能较高)
- 数据类型多样(不需要事先设计数据库,随用随取)
5.nosql的四大分类
- KV键值对
- 文档数据库
- 存储数据库
- 图形数据库
二、redis入门
1.什么是redis?
Redis(Remote Dictionary Server ),即远程字典服务 使用开源ANSI C语言编写、支持网络、基于内存或可持续的日志,Key-Value提供多种语言的数据库API。
2.reds能干什么?
- 内存存储、持久化、内存中是断电即失,所以说持久化很重要(rdb,aof)
- 效率高,可以用于高速缓存
- 发布订阅系统
- 地图信息分析
- 计时器、计数器(浏览量)
3.特性
1.多样的数据类型 2. 持久化 3. 事务
4.学习中需要用到的东西
1、官网:https://redis.io/ 2、中文网:http://www.redis.cn/
5.安装
https://blog.csdn.net/weixin_43099842/article/details/124965690?spm=1001.2014.3001.5501
6.性能测试
redis-benchmark是一个压力测试工具!
官方自带的性能测试工具!
redis-benchmark 命令参数,即可测试
首先需要保证redis-server服务开启,并且可以连通
参数如下: 使用下面语句测试 [huizi@localhost bin]$ ./redis-benchmark -h localhost -p 6379 -c 100 -n 100000
7.基础知识
redis默认有16个数据库,从0开始到15个,默认是第0个
可以在配置文件中查看
基本命令
select:切换数据库
dbsize:查看数据库大小
keys *::获取当前数据多有的key
flushdb:清除当前数据库
flushall:清除所有数据库内容
Redis 是单线程的
Redis是很快的,官方表示,Redis是基于内存操作的,所以CPU并不是Reids的性能瓶颈,Reids的瓶颈是根据机器的内存和网络带宽(请求都需要经过网络)来的。
既然可以使用单线程来实现,所以就使用了单线程!
Redis 是 C 语言写的,官方提供的数据为 100000+ 的QPS(每秒请求数),完全不比同样是 key-value的Memcache差!
1、误区1:高性能的服务器一定是多线程的?不一定
2、误区2:多线程(CPU会上下文切换,这是耗时的操作!)一定比单线程效率高!是不对的。
需要去了解 CPU、内存、硬盘的速度!
三、redis五大数据类型
127.0.0.1:6379> keys * # 查看当前数据库所有的key
(empty list or set)
127.0.0.1:6379> set name zxh # set一个key-value
OK
127.0.0.1:6379> set age 1
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,1表示第0个数据库,从小到大 这个和select有区别
(integer) 1
127.0.0.1:6379> keys *
1) "age"
127.0.0.1:6379> get age # 根据key获取值
"1"
127.0.0.1:6379> set name zxh
OK
127.0.0.1:6379> expire name 10 # 设置key的过期时间
(integer) 1
127.0.0.1:6379> ttl name # 查看当前key的剩余时间
(integer) 7
127.0.0.1:6379> ttl name
(integer) 6
127.0.0.1:6379> ttl name
(integer) 5
127.0.0.1:6379> ttl name
(integer) 5
127.0.0.1:6379> ttl name
(integer) 1
127.0.0.1:6379> ttl name
(integer) -2
127.0.0.1:6379> get name
(nil)
127.0.0.1:6379> keys *
1) "age"
127.0.0.1:6379> type age # 查看当前key的类型
1.String 字符串
字符串常用命令
1.1 追加、判断是否存在、获取长度
set key value:设置值
get key value:获取值
keys *:获取所以的key
append key value:追加字符串,如果当前key不存在,就相当于set一个key
strlen key:获取字符串的长度
exists key:判断某一个key是否存在
127.0.0.1:6379> keys *
1) "name"
127.0.0.1:6379> EXISTS name #判断key是否存在,不存在就是新建
(integer) 1
127.0.0.1:6379> append name hello # 追加数值
(integer) 10
127.0.0.1:6379> get name
"huizihello"
127.0.0.1:6379>
127.0.0.1:6379> STRLEN name # 获取key的value字符串长度
(integer) 10
1.2 字符串类型为整数的增/减量
可能用作浏览量等等
incr key:自增 +1 decr key:自减 -1 incrby key increment:设置步长,指定增量! decrby key decrement:设置步长,指定减量!
127.0.0.1:6379> set view 0
OK
127.0.0.1:6379> INCR view
(integer) 1
127.0.0.1:6379> get view
"1"
127.0.0.1:6379> INCR view
(integer) 2
127.0.0.1:6379> get view
"2"
127.0.0.1:6379> DECR view
(integer) 1
127.0.0.1:6379> get viewe
(nil)
127.0.0.1:6379> get view
"1"
127.0.0.1:6379> INCRBY view 2
(integer) 3
127.0.0.1:6379> get view
"3"
127.0.0.1:6379> DECRBY view 3
(integer) 0
1.3 截取和替换
getrange key start end:字符串截取,比如 [0,5] 左右都是一个闭区间
setrange key offset value:字符串的替换,替换指定下标的字符
127.0.0.1:6379> getrange name 0 3 # 左右都是闭区间
"huiz"
127.0.0.1:6379> setrange name 4 i
(integer) 10
127.0.0.1:6379> get name
"huizihello"
1.4 设置时间
setex key seconds value:设置过期时间
ttl key:查看剩余时间
setnx key value:判断是否存在,再创建
127.0.0.1:6379> setnx age 19 # 如果key存在就不创建
(integer) 0
127.0.0.1:6379> get age
"18"
127.0.0.1:6379> setnx sex 1 # 如果key不存在就创建
(integer) 1
127.0.0.1:6379> keys *
1) "age"
2) "sex"
3) "name"
4) "view"
127.0.0.1:6379>
1.5 多个值的set 和获取get以及对象存储
mset [key value…]:同时设置多个k-v
mget [key …]:同时获取多个k-v
msetnx [key value…]:设置多个k-v,msetnx是一个原子操作,要么一起成功,要么一起失败,用于分布式锁
127.0.0.1:6379> mset k1 v1 k2 v2 k3 v3 # 同时设置多个k-v
OK
127.0.0.1:6379> keys *
1) "k1"
2) "k2"
3) "age"
4) "name"
5) "sex"
6) "k3"
7) "view"
127.0.0.1:6379> mget k1 k2 k3 # 同时获取多个key
1) "v1"
2) "v2"
3) "v3"
127.0.0.1:6379> msetnx k1 v1 k4 v4 # 设置多个key,要么成功,要么失败
(integer) 0
可以使用 user:1:name 这种key方式来表示 user1对象的name属性,用来代替json字符串
# 如果保存 user1:{name:zhangsan,age:18} json表示的对象 那么可以下面这么做。足以看出redis是非常强大的
127.0.0.1:6379> mset user:1:name zhansgan user:1:age 18
OK
127.0.0.1:6379> keys *
1) "age"
2) "k2"
3) "user:1:name"
4) "name"
5) "view"
6) "user:1:age"
7) "k1"
8) "sex"
9) "k3"
127.0.0.1:6379>
1.6 先获取后设置
getset key value:先获取之前存放的值,再设置,如果存在就是覆盖
127.0.0.1:6379> getset age 18
"18"
127.0.0.1:6379> get age
"18"
127.0.0.1:6379> get age 17
(error) ERR wrong number of arguments for 'get' command
127.0.0.1:6379> getset age 17
"18"
127.0.0.1:6379> get age
"17"
应用场景
String类似的使用场景:value除了是我们的字符串还可以是我们的数字!
- 计数器
- 统计多单位的数量
- 粉丝数
- 对象缓存存储
2.List
在redlis中的List类型,可以玩成栈、队列、阻塞队列 看下面的图 左端进,右端出 ---->队列 左端进,左端出 ---->栈 所有的List命令基本都是l开头的
##################################################
lpush key value [value…]:将一个或多个值,插入到列表的头部(也就是左端)
lrange key start end:取list中的值!先进后出,后进先出,可以看出一条水平线,从左端依次塞入,做左端依次拿出
rpush key value [value…]:从将一个或多个值,从列表的右端放入
##################################################
lpop key:移除列表的第一元素,从左端移除
rpop key:移除列表的最后一个元素,从右端移除
##################################################
lindex key index:通过下标获取列表的值
llen key:获取列表的长度/大小
##################################################
lrem key count value:移除列表中指定个数的指定的值,精准匹配
##################################################
ltrim key start end:通过下标指定长度,截取列表的值,并且用截取的列表改变原列表
##################################################
rpoplpush resouce destination:移除原列表最后一个元素,将它移动到新的列表中(做左端放入)
##################################################
lset key index value:替换列表中指定下标的值
linsert key before|after pivot value:在指定的值前面或者后面插入值
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
1) "three"
2) "two"
3) "one"
127.0.0.1:6379> RPUSH list four
(integer) 4
127.0.0.1:6379> LRANGE list 0 -1
1) "three"
2) "two"
3) "one"
4) "four"
###########################################################################################################
127.0.0.1:6379> lpop list
"three"
127.0.0.1:6379> rpop list
"four"
127.0.0.1:6379> LRANGE list 0 -1
1) "two"
2) "one"
###########################################################################################################
127.0.0.1:6379> lindex list 0
"two"
127.0.0.1:6379> llen list
(integer) 2
127.0.0.1:6379> lrange list 0 -1
1) "one"
2) "one"
3) "one"
4) "one"
###########################################################################################################
127.0.0.1:6379> lrem list 3 one
(integer) 3
127.0.0.1:6379> lrange list 0 -1
1) "one"
###########################################################################################################
127.0.0.1:6379> ltrim list 0 1
OK
127.0.0.1:6379> lrange list 0 -1
1) "one"
2) "one"
###########################################################################################################
127.0.0.1:6379> RPOPLPUSH list mylist
"one"
127.0.0.1:6379> keys *
1) "mylist"
2) "list"
127.0.0.1:6379> EXISTS mylist
(integer) 1
127.0.0.1:6379> lrange list 0 -1
1) "one"
###########################################################################################################
127.0.0.1:6379> lset mylist 0 two
OK
127.0.0.1:6379> LRANGE mylist 0 -1
1) "two"
###########################################################################################################
127.0.0.1:6379> LINSERT list before one hello
(integer) 2
127.0.0.1:6379> lrange list 0 -1
1) "hello"
2) "one"
127.0.0.1:6379> LINSERT list after one hello1
(integer) 3
127.0.0.1:6379> lrange list 0 -1
1) "hello"
2) "one"
3) "hello1"
他实际上是一个链表,before Node after , left,right 都可以插入值
如果key 不存在,创建新的链表
如果key存在,新增内容
如果移除了所有值,空链表,也代表不存在!
在两边插入或者改动值,效率最高! 中间元素,相对来说效率会低一点~
消息排队!消息队列 (Lpush Rpop), 栈( Lpush Lpop)!
3.Set
set中的值是不能重复的!set命令一般是以s开头
sadd key meber [member…]:在set集合中添加元素
smembers key:查看指定set集合的所有值
sismember key member:判断某一个值是否在集合中
scard key:获取指定set集合的大小
srem key member [member…]:移除set集合中指定的一个或多个元素
srandmember key count:随机获取set集合中的一个或者多个元素
spop key cout:随机删除一个或者多个元素
smove resouce destination member:将集合中指定的元素移动到另一个集合中
sdiff key [key…]:差集,保留在第一个集合中其他集合里没有的值
sinter key [key…]:交集
sunion key [key…]:并集
# sadd key meber [member...]:在set集合中添加元素
# smembers key:查看指定set集合的所有值
127.0.0.1:6379> sadd myset hello
(integer) 1
127.0.0.1:6379> sadd myset "hello"
(integer) 0
127.0.0.1:6379> SMEMBERS myset
1) "hello"
#sismember key member:判断某一个值是否在集合中
127.0.0.1:6379> SISMEMBER myset hello
(integer) 1
127.0.0.1:6379> SISMEMBER myset hello
(integer) 1
127.0.0.1:6379> SISMEMBER myset hello1
(integer) 0
#scard key:获取指定set集合的大小
127.0.0.1:6379> scard myset
(integer) 1
#srem key member [member...]:移除set集合中指定的一个或多个元素
127.0.0.1:6379> srem myset hello
(integer) 1
127.0.0.1:6379> smembers myset
(empty array)
#srandmember key count:随机获取set集合中的一个或者多个元素
127.0.0.1:6379> sadd myset huizi huizi1 huzi2 huizi3 huizi4
(integer) 5
127.0.0.1:6379> srandmember myset 1
1) "huzi2"
127.0.0.1:6379> srandmember myset 1
1) "huzi2"
127.0.0.1:6379> srandmember myset 1
1) "huizi1"
#spop key cout:随机删除一个或者多个元素
127.0.0.1:6379> spop myset 1
1) "huizi3"
127.0.0.1:6379> smembers myset
1) "huizi"
2) "huzi2"
3) "huizi1"
4) "huizi4"
#smove resouce destination member:将集合中指定的元素移动到另一个集合中
127.0.0.1:6379> smove myset myset2 huizi
(integer) 1
127.0.0.1:6379> smembers myset2
1) "huizi"
#sdiff key [key...]:差集,保留在第一个集合中其他集合里没有的值
# myset{huizi、huizi1、huizi2、huzi4}和myset2 {huizi} 差集为{huizi1、huizi2、huzi4}
127.0.0.1:6379> sdiff myset myset2
1) "huizi1"
2) "huzi2"
3) "huizi4"
#sinter key [key...]:交集
127.0.0.1:6379> sinter myset myset2
1) "huizi"
#sunion key [key...]:并集
127.0.0.1:6379> sadd myset2 huizi6
(integer) 1
127.0.0.1:6379> smembers myset2
1) "huizi6"
2) "huizi"
127.0.0.1:6379> sunion myset myset2
1) "huzi2"
2) "huizi4"
3) "huizi"
4) "huizi6"
5) "huizi1"
可以应用在共同关注,共同爱好,随机抽奖应用场景中。
4.Hash
hash类型:相当于map集合,原来存储的是 key-value,现在变成 key-map!本质和String类型没有太大区别,还是一个简单的k-v!
hset key field value:存放一个具体的 k-v
hget key field:获取key中某一个属性值
hmset key field value [field value…]:存放一个或多个 k-v
hmget key field [field…]:获取key中一个或多个属性值
hdel key field [field…]:删除key中一个或多个属性值
hgetall key:获取key的全部的数据,以键值对形式显示
hlen key:获取map的长度
hexists key field:判断map是否有对应的属性
hkeys key:获取map所有的key
hvals key:获取map所有的value
hincrby key field increment:对map中的整数类型进行增量
hsetnx key field value:判断map中是否有对应的属性,如果没有进行存储
# hset key field value:存放一个具体的 k-v
# hget key field:获取key中某一个属性值
# hmset key field value [field value...]:存放一个或多个 k-v
# hmget key field [field....]:获取key中一个或多个属性值
127.0.0.1:6379> hset myhash field1 hello
(integer) 1
127.0.0.1:6379> hget myhash field
(nil)
127.0.0.1:6379> hget myhash field1
"hello"
127.0.0.1:6379> hmset myhash field2 hello2 field3 hello3
OK
127.0.0.1:6379> hmget myhash field field2
1) (nil)
2) "hello2"
# hdel key field [field...]:删除key中一个或多个属性值
# hgetall key:获取key的全部的数据,以键值对形式显示
127.0.0.1:6379> hdel myhash field1
(integer) 1
127.0.0.1:6379> hgetall myhash
1) "field2"
2) "hello2"
3) "field3"
4) "hello3"
# hlen key:获取map的长度
# hexists key field:判断map是否有对应的属性
127.0.0.1:6379> hlen myhash
(integer) 2
127.0.0.1:6379
# hkeys key:获取map所有的key
# hvals key:获取map所有的value
127.0.0.1:6379> hkeys myhash
1) "field2"
2) "field3"
127.0.0.1:6379> hvals myhash
1) "hello2"
2) "hello3"
# hincrby key field increment:对map中的整数类型进行增量
127.0.0.1:6379> hset myhash field5 5
(integer) 1
127.0.0.1:6379> hincrby myhash field5 1
(integer) 6
# hsetnx key field value:判断map中是否有对应的属性,如果没有进行存储
127.0.0.1:6379> hsetnx myhash field5 1
(integer) 0 # 表示已经存在
127.0.0.1:6379> hsetnx myhash field4 2
(integer) 1 # 表示不存在,然后进行存储
hash主要用于存储用户信息之类的,经常变动的信息!hash更适合对象的存储,String类型更适合字符串存储!
127.0.0.1:6379> hset user:1 name huizi
(integer) 1
127.0.0.1:6379> hget user:1 name
"huizi"
5.Zset(有序集合)
Zset就是在set集合上,增加了一个值,比如:set k1 v1,现在是zset k1 score1 v1
我们就可以针对score1 这个值进行一些操作:比如排序
zadd key score member [score member…]:添加一个或者多个元素
zrange key start end [withscores]:指定区间获取set集合的元素,可以设置是否显示score字段
zrangebyscore key min max [withscores]:根据指定的score进行升序排列
zrevrange key start stop [withscores]:根据指定的score进行降序排列
zrem key member [member…]:删除一个或者多个元素
zcard key:获取set集合的长度/大小
zcount key min max:统计个数,按照score属性的区间进行,在[min,max]之间的个数
# zadd key score member [score member...]:添加一个或者多个元素 # zrange key start end [withscores]:指定区间获取set集合的元素,可以设置是否显示score字段 127.0.0.1:6379> zadd myzset 1 one (integer) 1 127.0.0.1:6379> zadd myzset 2 two 3 three (integer) 2 127.0.0.1:6379> zrange myzset 0 -1 1) "one" 2) "two" 3) "three" # zrangebyscore key min max [withscores]:根据指定的score进行升序排列 # zrevrange key start stop [withscores]:根据指定的score进行降序排列 127.0.0.1:6379> zadd salary 2500 xiaohong (integer) 1 127.0.0.1:6379> zadd salary 3000 xiaowang (integer) 1 127.0.0.1:6379> zadd salary 3100 xiaozhang (integer) 1 127.0.0.1:6379> zrangebyscore salary -inf +inf 1) "xiaohong" 2) "xiaowang" 3) "xiaozhang" 127.0.0.1:6379> zrangebyscore salary -inf +inf withscores # 带上 withscores 就带上scores了 1) "xiaohong" 标签:
sub4p插头连接器