Redis学习笔记
Posted 蜜桃婷婷酱
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Redis学习笔记相关的知识,希望对你有一定的参考价值。
学习内容:数据库发展史(单机mysql的演进),NoSql,Redis的概念 数据库发展史,关系数据库和非关系数据库的关系和差别,Redis基本命令,基本数据类型,事务锁,集成Java(Jedis,SpringBoot自定义模板,封装util工具类等),持久化方式,发布订阅,主从复制,哨兵模式,基本配置,场景情况,缓存异常基本处理等
数据库发展史
前言:现在是大数据时代,互联网需求比90年更大(90年网站的访问量一般不会太大,单个数据库足够),普通的mysql满足不了,数据库单表数据量超过三百万所以分离读写操作(数据库主要就是进行读写操作),缓存可以有效避免用户对数据库的直接访问减少压力(mysql单表数据300万以上就一定要建立索引!).缓存也从传统的memcached交换成新的缓存技术redis
关于数据库的写的发展:
早些年Myisam:表锁(每次查询只锁这一张表),十分影响效率!高并发的时候会出现严重的锁问题
后来转战Innodb:行锁(每次查询只锁这一行)
慢慢的就开始使用分库分表来解决写的压力,Mysql在那个年代推出了表分区!但是并没有多少公司使用
Mysql的集群,很好的满足了那个年代的所有需求
如今的年代(大数据年代)
Mysql等关系型数据库就不够用了,数据量很大,变化也很快(微博热搜,排行榜等)
比如一篇文章,它的正在浏览量10w+,实现机制就是先把它存在redis中,过一段时间进行持久化
Mysq有的人会用它存储一些大的文件(数据),博客,图片,这时候效率就低了,如果有一种数据库专门用来存储这些东西,那么会极力减少Mysql的压力,那我们就研究如何处理这些问题,这时候关系数据库就无法实现了,大数据IO压力大,表几乎无法更改的(比如我有一亿条数据,这时候动态加一个列,无法实现),
关系型数据库什么意思?
关系型数据库:就好比我们的表格,是由行和列来记录的
关系型数据库,是指采用了关系模型来组织数据的数据库,其以行和列的形式存储数据,以便于用户理解,关系型数据库这一系列的行和列被称为表,一组表组成了数据库。”
1.Redis
Redis(Remote Dictionary Server ),即远程字典服务,是一个开源的使用ANSI C语言编写、支持网络、可基于内存亦可持久化的日志型、Key-Value数据库,并提供多种语言的API。从2010年3月15日起,Redis的开发工作由VMware主持。从2013年5月开始,Redis的开发由Pivotal赞助。
1 . Redis关键字
开源的,C语言编写的,支持多种语言(Java,Go,C,Python等等),基于内存可持久化的日志型键值对应(key-value)数据库,主要做缓存处理
2. 缓存以及缓存流程
缓存可以减少直接对数据库的访问量压力,流程为:用户发送请求访问数据库,接收到请求后首先会判断一下缓存中有没有该数据,如果没有的话就访问数据库并且把得到的数据相应返回给用户,同时把数据存到缓存中下次请求相同的数据就直接从缓存中那,如果有的话,那就直接取缓存中的数据不用再访问数据库
3. Redis端口号
6379
4. Windows安装使用(已经停更很长时间,推荐使用linux使用redis!!!)
去github下载压缩包,解压即可,启动的时候首先启动redis.server服务,然后启动redis.cli客户端
5. 常用命令以及Redis-key的一些操作
- ping(有没有连接到.返回pong表示连接成功)
- set get(set name wyh get name)
- 清除全部的数据库内容 flushall
- 清除当前数据库flushdb
- keys(*)查看全部的键
- exists(key) 查看键是否存在,存在的话返回1,不存在返回0
- select (数据库num)进行切换数据库
- clear清屏
- move key numb (键,移动到那个数据库) 移动属性到指定的数据库
- expire (name 10 )设置某个键的过期时间(单位是秒s)
- ttl (key) 查看当前某个键的剩余时间,过期的话返回负数
- type 查看数据类型 type key
- shutdown 关闭服务连接 也就是我们的server
- save 保存文件
- exit退出我们的客户端
127.0.0.1:6379[5]> ping #测试连接
PONG #连接成功
127.0.0.1:6379[1]> select 0 #切换数据库0
OK
127.0.0.1:6379> select 1 #切换数据库0
OK
127.0.0.1:6379[1]> set name wyh #设置key键
OK
127.0.0.1:6379[1]> set age 22 #设置key键
OK
127.0.0.1:6379[1]> keys * #查看全部的键
1) "name"
2) "age"
127.0.0.1:6379[1]> get name
"wyh"
127.0.0.1:6379[1]> exists age #判断是否存在
(integer) 1
127.0.0.1:6379[1]> flushdb # 刷新当期数据库
OK
127.0.0.1:6379[1]> flushall #刷新全部数据库
OK
127.0.0.1:6379[1]> clear #清空
127.0.0.1:6379[2]> set animal dog #设置属性
OK
127.0.0.1:6379[2]> move animal 5 #把animal键移动到数据库5
(integer) 1
127.0.0.1:6379[2]> keys * #查看全部的键
1) "age"
127.0.0.1:6379[2]> select 5 #切换到数据库5
OK
127.0.0.1:6379[5]> keys * #查看全部的键
1) "animal"
127.0.0.1:6379[2]> expire name 10 #设置过期时间10秒
(integer) 1 #成功的话返回1 不成功返回0
127.0.0.1:6379[2]> ttl name #查看剩余过期时间
(integer) 6
127.0.0.1:6379[2]> ttl name #查看当前key的剩余过期时间
(integer) 1
127.0.0.1:6379[2]> ttl name #查看当前key的剩余过期时间
(integer) -2 #已经过期2秒
127.0.0.1:6379[2]> get name #查看name,已经过期
(nil) #没有了,说明已经过期
127.0.0.1:6379[2]> type age #查看key的类型
string
127.0.0.1:6379[2]> type name #查看key的类型
string
127.0.0.1:6379[2]> save #保存配置
ok
127.0.0.1:6379[2]> shutdown #关闭服务连接 也就是我们的server
6. redis-benchmark官方自带的压力测试工具
以上是它在windows里面的位置,因为我目前没配置linux
redis-benchmark -h 127.0.0.1 -p 6379 -c 50 -n 10000 ##压测命令
100000 requests completed in 0.72 seconds #对我们的10万个请求进行写入测试在0.72秒完成
50 parallel clients # 50个并发客户端
3 bytes payload #每次写入三个字节
keep alive: 1 #只有一台服务器来处理这些请求,单机性能
99.95% <= 13 milliseconds
99.96% <= 14 milliseconds
99.97% <= 15 milliseconds
99.98% <= 16 milliseconds
99.99% <= 17 milliseconds
99.99% <= 18 milliseconds
100.00% <= 19 milliseconds
100.00% <= 19 milliseconds #所以请求在19秒内完成
142247.52 requests per second #一秒处理142247次请求
7. Redis的5种基本数据类型
1 String(字符串)
String类型使用场景
value除了是我们的字符串还可以是我们的数字,redis会自动帮我们辨别转化
- 计数器
- 统计多单位的数量
- 粉丝数,关注数,浏览量
- 对象缓存存储
String类型常用方法
1.append append (key 给哪个键 string 追加什么内容)追加字符串,追加成功后返回当期这个key的长度, 如果当前追加的这个key不存在就新创建一个key
127.0.0.1:6379[2]> get name #查看wyh
"wyh"
127.0.0.1:6379[2]> append name yyt #给wyh这个键拼接字符串
(integer) 6 #返回当前这个key追加内容后的长度
127.0.0.1:6379[2]> append name1 zhangsan #如果当前追加的这个key不存在就新创建一个key
(integer) 8 #返回当前这个key追加内容后的长度
2 strlen strlen (key) 查看某个key的长度
127.0.0.1:6379[2]> strlen name #查看某个key的长度
(integer) 6 #返回这个key的长度
127.0.0.1:6379[2]> strlen name2 #查看某个不存在key的长度
(integer) 0 #不存在的话返回0
127.0.0.1:6379[2]> set views 0
OK
3 incr incr(key)自增 默认自增1
场景:浏览量,当前观看人数,都是它实现的,相当于java的i++
127.0.0.1:6379[2]> decr views #让views这个key自减1
(integer) 3
127.0.0.1:6379[2]> decr views #让views这个key自减1
(integer) 2
127.0.0.1:6379[2]> decr views #让views这个key自减1
(integer) 1
127.0.0.1:6379[2]> decr views #让views这个key自减1
(integer) 0
127.0.0.1:6379[2]> decr views #让views这个key自减1
(integer) -1 #可以为负数
127.0.0.1:6379[2]> get views #查看views这个Key
"-1"
4 decr decr(key)自减,默认每次减少1,可以为负数
127.0.0.1:6379[2]> decr views #让views这个key自减1
(integer) 3
127.0.0.1:6379[2]> decr views #让views这个key自减1
(integer) 2
127.0.0.1:6379[2]> decr views #让views这个key自减1
(integer) 1
127.0.0.1:6379[2]> decr views #让views这个key自减1
(integer) 0
127.0.0.1:6379[2]> decr views #让views这个key自减1
(integer) -1 #可以为负数
127.0.0.1:6379[2]> get views #查看views这个Key
"-1"
5 incrby incrby (key) (numb)让某个键一次性步长几个长度
127.0.0.1:6379[2]> incrby views 10 #一次性步长10
(integer) 9
6 decrby decrby (key) (numb)让某个键一次性步减几个长度
127.0.0.1:6379[2]> decrby views 10 #一次性步减10
(integer) -1
7 range range (key) (index从哪里开始,长度也是从0开始的) (截取几位)查看区间指定的值,类似substring截取,如果截取的这个参数为-1显示全部的字符串,其实和get key是一样的作业
127.0.0.1:6379[2]> set key1 hello,weiyihe #创建一个key
OK
127.0.0.1:6379[2]> getrange key1 0 3 #查看区间指定的值(从0开始,数3位,也就是前四位)
"hell"
127.0.0.1:6379[2]> getrange key1 0 -1 ##如果截取的这个参数为-1显示全部的字符串 和get key是一样的
"hello,weiyihe"
8 setrange setrange(key)(index)(value)把key按照指定的下表替换成指定的值
其实就是java中的replace替换
127.0.0.1:6379[2]> set key3 abc #设置一个新的key
OK
127.0.0.1:6379[2]> setrange key3 0 x #把key3按照指定的下表和值进行替换(把第0位换成x)
(integer) 3 #替换之后得到最终结果的长度
127.0.0.1:6379[2]> get key3 #
"xbc" # 查看key3
127.0.0.1:6379[2]> setrange key3 0 xxx # #把key3按照指定的下表和值进行替换(把第0位换成xxx)
(integer) 3 # 替换之后得到最终结果的长度
127.0.0.1:6379[2]> get key3 #查看key3
"xxx"
9 setex settex(set with expire) 设置过期时间 setex(key) (time,存活时间,一般都是秒s)(key的value)
127.0.0.1:6379[2]> setex key3 30 "hello" #设置一个值为hello的键Key3,有效期30秒
OK
127.0.0.1:6379[2]> get key3 #查看key3
"hello"
127.0.0.1:6379[2]> ttl key3 #查看当期key3的有效时间
(integer) 19 #19s(秒)
127.0.0.1:6379[2]> ttl key3 #查看当期key3的有效时间
(integer) 18 #18s(秒)
127.0.0.1:6379[2]> get key3 #查看key3
(nil) #没了(过期了)
127.0.0.1:6379[2]> ttl key3 #查看key3
(integer) -2 #没了(过期了)
11 setnx settex(set if not exist) 不存在设置 (在分布式锁中经常使用) setnx (key) (key 的value)成功的话返回1(一般成功就创建一个新的key,或者把key的value改变),不成功返回0,不成功因为设置那个key已经存在了
127.0.0.1:6379[2]> setnx mykey redis #设置一个叫mykey的键
(integer) 1 #成功返回1
127.0.0.1:6379[2]> get key3
(nil)
127.0.0.1:6379[2]> setnx mykey mysql #重新设置mykey的键,不成功,因为已经有了一个叫mykey的key
(integer) 0 #不成功返回0
127.0.0.1:6379[2]> get mykey #查看key mykey
"redis"
127.0.0.1:6379[2]> setnx mykey1 mysql #设置一个叫mykey1的键
(integer) 1 #成功,因为没有叫mykey1的key
127.0.0.1:6379[2]> get mykey1 #查看key mykey1
"mysql"
12 mset mset (k1 v1)( k2 v2) (k3 v3)一次性设置多个键值对
127.0.0.1:6379[2]> mset k1 v1 k2 v2 k3 v3 #一次性设置三个键值对(k1 v1)( k2 v2) (k3 v3)
OK
127.0.0.1:6379[2]> keys * #查看全部的值
1) "k3"
2) "k2"
3) "k1"
13 mget mget (k1 k2 k3)一次性获取多个key的值
127.0.0.1:6379[2]> mget k1 k2 k3 #一次性获取多个key的值
1) "v1"
2) "v2"
3) "v3"
14 msetnx msetnx(key value)msetnx是一个原子性操作(要么全部成功,要么全部失败)
127.0.0.1:6379[2]> mset k1 v1 k2 v2 k3 v3 #一次性获取多个key的值
OK
127.0.0.1:6379[2]> keys #查看全部的key
1) "k3"
2) "k2"
3) "k1"
127.0.0.1:6379[2]> mget k1 k2 k3 #一次查看三个key
1) "v1"
2) "v2"
3) "v3"
127.0.0.1:6379[2]> msetnx k1 v1 k4 v4 #注意,这时候k1 v1已经存在,但是k4 v4不存在,返回结果为0失败,说明该操作具有原子性(要么全部成功,要不全部失败)
(integer) 0 #操作失败
127.0.0.1:6379[2]> get k4 #查看key4
(nil) #没有key4
15msetnx 扩展
开发场景:一般创建对象 set user:1name:“张三”,age:10设置一个user:1对象.它的值为一个json字符串来保存一个对象
这里的key是一个巧妙的设计 user:id:filed如此设计在redis中是完全可以的
127.0.0.1:6379[2]> mset user:1:name zhangsan user:1:age 10 #设置一个user1对象,它的name是zhangsan,age是10
OK
127.0.0.1:6379[2]> mset user:2:name lisi user:2:age 20 #设置一个user2对象,它的name是lisi,age是20
OK
127.0.0.1:6379[2]> mget user:1:name user:1:age #获取user1对象的name和age
1) "zhangsan"
2) "10"
127.0.0.1:6379[2]> mget user:2:name user:2:age #获取user2对象的name和age
1) "lisi"
2) "20"
127.0.0.1:6379[2]> mset user1:name zhangsan user1:age 10 #创建一个user1多key,json字符串的值
OK
127.0.0.1:6379[2]> get user1:name #单个获取user1的name
"zhangsan"
127.0.0.1:6379[2]> get user1:age #单个获取user1的age
"10"
127.0.0.1:6379[2]> mget user1:age user1:name #一次性获取m1的name和age
1) "10"
2) "zhangsan"
16 getset getset(key)(value) 先get再set,如果不存在值则返回null,如果存在值则获取原来的值并且设置新的值
127.0.0.1:6379[2]> getset db redis #先get再get一个key(db)
(nil) #因为一开始没有db这个key
127.0.0.1:6379[2]> get db #获取db这个key
"redis"
127.0.0.1:6379[2]> getset db mysql #setdb这个key
"redis"
127.0.0.1:6379[2]> get db #重新获取db这个key发现它已经被set了
"mysql"
2 Hash(哈希)
map集合,key-map,这时候这个值是一个map集合
hash的命令都是以"h"开头的
hash本质和string没有多大区别
hash的应用场景:存储变更的对象,尤其是用户信息的保存,经常变动的信息.更适合对象的存储,String更加适合字符串的存储
127.0.0.1:6379[2]> hset user:1 name wyh #存储一个用户
(integer) 1
127.0.0.1:6379[2]> hget user:1 name #获取用户名
"wyh"
1 hset(hash)(key)(value)存键值对的hash数据
127.0.0.1:6379[2]> hset user 1 wyh #创建一个键值对的hash名为user,给它复制key为1value为wyh的元素
(integer) 1
127.0.0.1:6379[2]> hset user 2 yyt #创建一个键值对的hash名为user,给它复制key为2value为yyt的元素
(integer) 1
127.0.0.1:6379[2]> hget user 1 #从user这个hash中key为1的元素
"wyh"
127.0.0.1:6379[2]> hget user 2 #从user这个hash中key为1的元素
"yyt"
2 hget(hash)(key)(value)根据key取对应的hash里面的元素
127.0.0.1:6379[2]> hset user 1 wyh #创建一个键值对的hash名为user,给它复制key为1value为wyh的元素
(integer) 1
127.0.0.1:6379[2]> hset user 2 yyt #创建一个键值对的hash名为user,给它复制key为2value为yyt的元素
(integer) 1
127.0.0.1:6379[2]> hget user 1 #从user这个hash中key为1的元素
"wyh"
127.0.0.1:6379[2]> hget user 2 #从user这个hash中key为1的元素
"yyt"
3 hgetall(hash)获取hash的全部属性
127.0.0.1:6379[2]> hgetall user #获取user的全部对象
1) "1"
2) "wyh"
3) "2"
4) "yyt"
4 hmset(hash)(key1)(value1)(key2)(value2)一次性set多个key value
127.0.0.1:6379[2]> hmset hash 1 a 2 b #一次性存储多个值
OK
127.0.0.1:6379[2]> hmget hash 1 2 #一次性取多个值
1) "a"
2) "b"
5 hmget(hash)(key1)(key2)一次性根据key取好几个值
127.0.0.1:6379[2]> hmset hash 1 a 2 b #一次性存储多个值
OK
127.0.0.1:6379[2]> hmget hash 1 2 #一次性取多个值
1) "a"
2) "b
6 hdel(hash)(key)根据key删除hash中的属性,对应的value值也就没有了
127.0.0.1:6379[2]> hdel hash 1 #删除key为1的这个属性
(integer) 1
127.0.0.1:6379[2]> hgetall hash #查看全部的属性
1) "2"
2) "b"
7 hlen(hash)查看这个hash中有多个属性(键值对)
127.0.0.1:6379[2]> hlen hash #查看有多少个属性(键值对)
(integer) 3 #三个
8 hexists (hash)(key)判断hash中是否存在这个key,返回1说明存在,返回0说明不存在
127.0.0.1:6379[2]> hexists hash 3 #判断是不是存在3这个key
(integer) 1 #返回1代表存在
127.0.0.1:6379[2]> hexists hash 33 #判断是不是存在3这个key
(integer) 0 #返回0代表不存在
9 hkeys (hash)查看全部的key
127.0.0.1:6379[2]> hkeys hash #查看全部的key
1) "2"
2) "1"
3) "3"
10 hvals(hash)查看全部的key
127.0.0.1:6379[2]> hvals hash #查看全部的values
1) "b"
2) "a"
3) "c"
11 hincrby (hash)(key)(count)给hash指定key对应的值自增(指定增减量)key是正数也可以是负数,负数的话就是减
127.0.0.1:6379[2]> hset hash id 5 #创建一个hash存储id为5的属性
(integer) 1
127.0.0.1:6379[2]> hincrby hash id 1 #给id为1的属性自增1
(integer) 6 #自增后元素为6
127.0.0.1:6379[2]> hincrby hash id 2 #给id为1的属性自增2
(integer) 8 #自增后元素为8
127.0.0.1:6379[2]> hincrby hash id -1 #给id为1的属性自增1
(integer) 7 #自减后元素为8
12 hsetnx (hash)(key)(value)添加hash元素, 如果这个hash存在就添加不了别的元素, 如果这个hash不存在就可以添加别的元素
127.0.0.1:6379[2]> hsetnx user id 1 #创建一个hash
(integer) 1
127.0.0.1:6379[2]> hsetnx user id 2 #如果这个hash存在就添加不了别的元素
(integer) 0
127.0.0.1:6379[2]> hsetnx user id 1 #如果这个hash存在就添加不了别的元素
(integer) 0
127.0.0.1:6379[2]> hsetnx user1 id 1 #如果这个hash不存在就可以添加别的元素
(integer) 1
3 List(列表)
list使用场景:可以把它用作成栈(lpush rpop左边进去 右边出来),队列,阻塞队列 ,消息排队,消息队列(lpush rpop)
所有的list命令都是以"l(L)"开头的
1 lpush lpush (list) (v1)(v2)(v3) 从左边一次性或者多次插入.也就是头部
127.0.0.1:6379[2]> lpush list 1 2 3 #创建一个新的list的list一次性添加三个值
(integer) 3 #返回当前这个list里面有几个元素
127.0.0.1:6379[2]> lrange list 0 -1 #查看这个list名为list里面的全部元素(0,-1查看全部)
1) "3"
2) "2"
3) "1"
127.0.0.1:6379[2Redis学习笔记Redis安装和启动