Redis这一篇就够了

一.概述

Redis是什么?
Redis是远程服务字典服务,是一个开源的使用ANSI C语言编写,支持网络,可基于内存亦可持久化的日志型,Key-Value数据库,并提供多种语言的API。
redis会周期性把更新的数据写入磁盘或把修改操作写入追加的记录文件,并且在此基础上实现了master-slave(主从)同步。免费开源,是NoSQL技术之一,也称为结构化数据库。
Redis能干嘛?

  1. 内存存储,持久化,内存中是断电即失,所以说持久化很重要
  2. 效率高,可用于高速缓存
  3. 发布订阅系统
  4. 地图信息分析
  5. 计时器,计数器

二.Redis的基本了解

官方文档:
英文官方文档:https://redis.io/
中文文档:http://www.redis.cn/
Redis-Key常用命令:
http://www.redis.cn/commands.html

127.0.0.1:6379> ping  #查看当前连接是否正常,正常返回PONG
PONG
127.0.0.1:6379> clear  #清楚当前控制台(为了更好的看到下面输入的命令)
127.0.0.1:6379> keys *  #查看当前库里所有的key
1) "db"
127.0.0.1:6379> FLUSHALL  #清空所有库的内容
OK
127.0.0.1:6379> set name dingdada  #添加一个key为‘name’ value为‘dingdada’的数据
OK
127.0.0.1:6379> get name  #查询key为‘name’的value值
"dingdada"
127.0.0.1:6379> EXISTS name  #判断当前key是否存在
127.0.0.1:6379> move name 1  #移除当前库1的key为‘name‘的数据

三.五大数据类型

1. Redis通用命令

在这里插入图片描述

2. Redis数据类型

2.1 String - 字符串类型

在这里插入图片描述

字符串命令:
在这里插入图片描述

String表面上是字符串,但其实他可以灵活的表示字符串,整数,浮点数3种值。Redis自动识别这3种值

127.0.0.1:6379> set key1 "hello world!"  #注意点:插入的数据中如果有空格的数据,请用“”双引号,否则会报错!
OK
127.0.0.1:6379> set key1 hello world!  #报错,因为在Redis中空格就是分隔符,相当于该参数已结束
(error) ERR syntax error
127.0.0.1:6379> set key1 hello,world!  #逗号是可以的
OK
127.0.0.1:6379> incr num  #指定key为‘num’的数据自增1,返回结果  相当于java中 i++
(integer) 1
127.0.0.1:6379> get num  #一般用来做文章浏览量、点赞数、收藏数等功能
"1"
127.0.0.1:6379> decr num  #可以一直减为负数~
(integer) -1
127.0.0.1:6379> decr num  #一般用来做文章取消点赞、取消收藏等功能
#截取
127.0.0.1:6379> GETRANGE key1 0 4  #截取字符串,相当于java中的subString,下标从0开始,不会改变原有数据
"hello"
127.0.0.1:6379> get key1
"hello world!"
127.0.0.1:6379> GETRANGE key1 0 -1  #0至-1相当于 get key1,效果一致,获取整条数据
#替换
"hello world!"
127.0.0.1:6379> SETRANGE key2 5 888  #此语句跟java中replace有点类似,下标也是从0开始,但是有区别:java中是指定替换字符,Redis中是从指定位置开始替换,替换的数据根据你所需替换的长度一致,返回值是替换后的长度
(integer) 14
127.0.0.1:6379> get key2
"hello888world!"
127.0.0.1:6379> SETRANGE key2 5 67  #该处只替换了两位
(integer) 14
127.0.0.1:6379> get key2
"hello678world!"
#设置过期时间,跟Expire的区别是前者设置已存在的key的过期时间,而setex是在创建的时候设置过期时间
127.0.0.1:6379> setex name1 15  dingdada  #新建一个key为‘name1’,值为‘dingdada’,过期时间为15秒的字符串数据
OK
127.0.0.1:6379> ttl name1  #查看key为‘name1’的key的过期时间
(integer) 6
#不存在设置
127.0.0.1:6379> setnx name2 dingdada2  #如果key为‘name2’不存在,新增数据,返回值1证明成功
(integer) 1
127.0.0.1:6379> get name2
"dingdada2"
127.0.0.1:6379> keys *
1) "name2"
127.0.0.1:6379> setnx name2 "dingdada3"  #如果key为‘name2’的已存在,设置失败,返回值0,也就是说这个跟set的区别是:set会替换原有的值,而setnx不会,存在即不设置,确保了数据误操作~
(integer) 0
127.0.0.1:6379> get name2
"dingdada2"

2.2 Hash - Hash键值类型

Hash类型用于存储结构化数据
在这里插入图片描述

键-键-值
Hash 命令:
在这里插入图片描述

2.3 List - 列表类型
List列表就是一系列字符串的“数组”,按插入顺序排序
List列表最大长度为2的32次方-1,可以包含40亿个元素
List 命令
在这里插入图片描述

小结:
实际上是一个链表,before Node after , left,right 都可以插入值
如果key 不存在,创建新的链表
如果key存在,新增内容
如果移除了所有值,空链表,也代表不存在!
在两边插入或者改动值,效率最高! 中间元素,相对来说效率会低一点
消息排队!消息队列 (Lpush Rpop), 栈( Lpush Lpop)!

2.4 Set - 集合类型

Set集合是字符串的无序集合,集合成员是唯一的
在这里插入图片描述

2.5 Zset - 有序集合类型

Zset集合是字符串的有序集合,集合成员是唯一的
它的实质是每个数据对应了分数
在这里插入图片描述

总结:成绩表排序,工资表排序,年龄排序需求可以用zset来实现

四.三大特殊数据类型的学习和理解

1.Geospati:地理位置

城市维度查询:https://jingweidu.bmcx.com/
注意:
两极无法直接添加,我们一般会下载城市数据,直接通过java程序一次性导入
有效的经度从-180度到180度。
有效的纬度从-85.05112878度到85.05112878度。
m 为米。km 为千米。mi 为英里。ft 为英尺。
在这里插入图片描述

实际需求中,我们可以用来查询附近的人,计算两人之间的距离等。当然,那些所需的维度我们肯定要结合java代码来一次导入,手动查询和录入太过浪费时间。

2.Hyperloglog:基数

什么是基数?
数学层面上指两个数集中不重复的元素
但在redis中,可能会有一定误差,官方给的误差率为0.81%
Hyperloglog优点:占用的内存是固定的,2^64个元素,相等于只需要12kb的内存即可。效率高。
在这里插入图片描述

实际需求中,运行一定的误差值,我们可以使用技术统计来计算,效率非常高,如网站访问量,就可以利用Hyperloglog来进行计算统计

3.Bitmap:位存储

Bitmap位图,数据结构,都是操作二进制位来进行记录,只有0和1状态
在这里插入图片描述

实际需求中,可能需要我们统计用户的登录信息,员工的打开信息等。只要是事物的只有两种状态,我们都可以使用Bitmap来进行操作。

五.Redis中的事物和乐观锁如何实现?

1. 前言

事务的ACID:MySQL事务
在Redis中没有隔离级别的概念
在Redis单条命令式保证原子性,但是事物不保证原子性
乐观锁:
①当程序中可能出现并发的情况时,就需要保证在并发情况下数据的准确性,以此确保当前用户和其他用户一起操作时,所得到的结果和他单独操作时的结果是一样的。
②没有做好并发控制,就可能导致脏读、幻读和不可重复读等问题。
在Redis是可以实现乐观锁的!

2. Redis如何实现事务?

正常执行事务

127.0.0.1:6379> multi  #开启事务
OK
127.0.0.1:6379> set name dingyongjun  #添加数据
QUEUED
127.0.0.1:6379> set age 26  #添加数据
QUEUED
127.0.0.1:6379> set high 172  #添加数据
QUEUED
127.0.0.1:6379> exec  执行事务
1) OK
2) OK
3) OK
127.0.0.1:6379> get name  #获取数据成功,证明事务执行成功
"dingyongjun"
127.0.0.1:6379> get age
"26"

放弃事务

127.0.0.1:6379> multi  #开启事务
OK
127.0.0.1:6379> set name dingyongjun  #添加数据
QUEUED
127.0.0.1:6379> set age 26  #添加数据
QUEUED
127.0.0.1:6379> discard  #放弃事务
OK
127.0.0.1:6379> get name  #不会执行事务里面的添加操作
(nil)

③编译时异常,代码有问题,或者命令有问题,所有的命令都不会被执行

127.0.0.1:6379> multi  #开启事务
OK
127.0.0.1:6379> set name dingyongjun  #添加数据
QUEUED
127.0.0.1:6379> set age 23  #添加数据
QUEUED
127.0.0.1:6379> getset name  #输入一个错误的命令,这时候已经报错了,但是这个还是进入了事务的队列当中
(error) ERR wrong number of arguments for 'getset' command
127.0.0.1:6379> set high 173  #添加数据
QUEUED
127.0.0.1:6379> exec  #执行事务,报错,并且所有的命令都不会执行
(error) EXECABORT Transaction discarded because of previous errors.
127.0.0.1:6379> get name  #获取数据为空,证明没有执行
(nil)

运行时异常,除了语法错误不会被执行且抛出异常后,其他的正确命令可以正常执行

127.0.0.1:6379> multi  #开启事务
OK
127.0.0.1:6379> set name dingyongjun  #添加字符串数据
QUEUED
127.0.0.1:6379> incr name  #对字符串数据进行自增操作
QUEUED
127.0.0.1:6379> set age 23  #添加数据
QUEUED
127.0.0.1:6379> get age  #获取数据
QUEUED 
127.0.0.1:6379> exec  #执行事务。虽然对字符串数据进行自增操作报错了,但是其他的命令还是可以正常执行的
1) OK
2) (error) ERR value is not an integer or out of range
3) OK
4) "23"
127.0.0.1:6379> get age  #获取数据成功
"23"

总结:由以上可以得出结论,redis是支持单条命令事务的,但是事务并不能保证原子性

3. Redis如何实现乐观锁

watch(‘监听’)

127.0.0.1:6379> set money 100  #添加金钱100
OK
127.0.0.1:6379> set cost 0  #添加花费0
OK
127.0.0.1:6379> watch money  #监控金钱
OK
127.0.0.1:6379> multi  #开启事务
OK
127.0.0.1:6379> DECRBY money 30  #金钱-30
QUEUED
127.0.0.1:6379> incrby cost 30  #花费+30
QUEUED
127.0.0.1:6379> exec  #执行事务,成功!这时候数据没有发生变动才可以成功
1) (integer) 70
2) (integer) 30

多线程测试watch
线程一

#线程1
127.0.0.1:6379> set money 100  #添加金钱100
OK
127.0.0.1:6379> set cost 0  #添加花费0
OK
127.0.0.1:6379> watch money  #开启监视(乐观锁)
OK 
127.0.0.1:6379> multi  #开启事务
OK
127.0.0.1:6379> DECRBY money 20  #金钱-20
QUEUED
127.0.0.1:6379> INCRBY cost 20   #花费+20
QUEUED
#这里先不要执行,先执行线程2来修改被监视的值
127.0.0.1:6379> exec  #执行报错,因为我们监视了money这个值,如果事务要对这个值进行操作前
#监视器会判断这个值是否正常,如果发生改变,事务执行失败!
(nil)

线程二:

#线程2,这个在事务执行前操作执行
127.0.0.1:6379> INCRBY money 20  #金钱+20
(integer) 120

总结:
悲观锁: 什么时候都会出问题,所以一直监视着,没有执行当前步骤完成前,不让任何线程执行,十分浪费性能!一般不使用!
乐观锁: 只有更新数据的时候去判断一下,在此期间是否有人修改过被监视的这个数据,没有的话正常执行事务,反之执行失败!

六.Redis线程相关知识

Redis 是单线程的,这意味着它在任何给定时刻只会执行一个操作。虽然 Redis 是单线程的,但它通过使用非阻塞 I/O 和基于事件驱动的设计来实现高性能和并发处理。
Redis 的单线程架构使其非常快速,因为它无需处理线程之间的竞争条件和锁定。相反,Redis 依靠高效的内存数据存储和快速的非阻塞 I/O 操作来提供高吞吐量和低延迟。此外,Redis 还使用了一些技术来确保数据的一致性和持久性,如写日志和定期的数据快照。
虽然 Redis 主进程是单线程的,但它可以在后台启动多个附加线程来执行不同的任务,如数据持久化和复制。这些附加线程不会影响主线程的性能,因为它们通常处于低优先级状态,并且它们的工作不会阻塞主线程的执行。这使得 Redis 能够在单个线程下实现高性能和并发处理,成为一个非常受欢迎的内存数据库和缓存服务器。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

夏日一凉

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值