Redis详解

1.redis入门

1)redis的基本概念:

redis是一种开源的,基于内存的和C/S,高性能的键值型NoSQL的基本数据库。可以用作数据库,缓存和消息中间的组件。端口号是6379。

2)关系型数据库+非关系型

关系型数据库 = 用 "表格" 存数据,像 Excel 一样

核心特点

  • 数据存在 表(table)

  • 表有固定的 列(字段),结构必须提前定义

  • 支持 SQL 语言 查询

  • 强调 事务、一致性、安全(钱、订单、用户信息必须用它)

  • 表和表之间可以 关联(外键)

典型代表

  • MySQL

  • Oracle

  • SQL Server

  • PostgreSQL

优点

  • 数据安全、严谨、不会乱

  • 支持复杂查询、事务(ACID)

  • 适合存结构化数据:用户、订单、商品

缺点

  • 扩展性差,大数据高并发吃力

  • 表结构改起来麻烦

  • 不适合存海量非结构化数据

非关系型数据库 = 不用表格存,灵活、快、高并发

NoSQL = Not Only SQL(不仅仅是 SQL)

核心特点

  • 没有固定表结构,想存什么存什么

  • 不强调严格关系

  • 追求 快、高并发、海量存储

  • 数据模型灵活:key-value、文档、列、图

四大类(你课件里也讲了)

  1. KV 键值型(Redis、Memcached)

  2. 文档型(MongoDB)

  3. 列存储(HBase)

  4. 图数据库(Neo4j,社交关系)

优点

  • 速度极快(Redis 纯内存)

  • 高并发轻松扛

  • 水平扩展强,大数据轻松应对

  • 结构灵活,随时加字段

缺点

  • 事务、一致性不如关系型数据库

  • 不适合存特别严谨的数据(如金融交易)

3)redis的基本操作

Redis默认有16个数据库,默认使用的是第0个数据库,可以通过select切换数据库。

select

切换数据库 格式:select index

sql 复制代码
127.2.2.1:6379> select 3  #切换数据库
OK

dbsize

查看数据的大小,格式:dbsize

sql 复制代码
127.0.0.1:6379[3]> DBSIZE  # 查看数据库的大小
(integer) 0
127.0.0.1:6379[3]> set name wangold
OK
127.0.0.1:6379[3]> set age 28
OK
127.0.0.1:6379[3]> DBSIZE
(integer) 2

keys

查看所有的 key,格式:keys *

sql 复制代码
127.0.0.1:6379[3]> KEYS *  #查看所有的key
1) "name"
2) "age"

flushdb flushall

清空当前数据库和清空所有的数据

sql 复制代码
127.0.0.1:6379[3]> FLUSHDB  #清空当前数据库
OK
127.0.0.1:6379[3]> KEYS *
(empty array)
127.0.0.1:6379[3]> FLUSHALL  #清空所有的数据库
OK

4)为什么redis是单线程的?

redis是很快的,官方标识,redis是基于内存操作的,cpu不是redis的性能瓶颈,redis的瓶颈就是根据机器的内存和网络宽带,既然可以使用单线程实现,就使用单线程了。
Redis为什么单线程还这么快?
误区1: 高性能的服务器一定是多线程的
误区2: 多线程(CPU上下文切换)一定比单线程效率高
核心: Redis是将所有的数据全部放在内存中的,所以说使用单线程去操作效率就是最高的,相比多
线程,减少了CPU上下文切换的耗时。对于内存系统来说,没有上下文切换效率就是最高的,多次读写
都是在一个CPU上的。

2.redis五个基本类型

redis---key

一、字符串(String)

定义:最基础类型,key = 字符串,value = 字符串 / 数字 / 二进制,最大 512MB。

  1. 基础操作
cpp 复制代码
# 1. 设置键值对
SET name "张三"

# 2. 获取值
GET name  # 返回 "张三"

# 3. 不存在才设置(分布式锁核心)
SETNX lock 1  # 成功返回1,失败返回0

# 4. 设置并指定过期时间(秒)
SETEX code 60 1234  # 60秒后自动删除

# 5. 批量设置/批量获取
MSET k1 v1 k2 v2 k3 v3
MGET k1 k2 k3  # 返回 v1 v2 v3

# 6. 删除键
DEL name
  1. 数值操作(原子性,高并发安全)
cpp 复制代码
SET num 10

# 自增1
INCR num  # 11

# 自减1
DECR num  # 10

# 自增指定数字
INCRBY num 5  # 15

# 自减指定数字
DECRBY num 5  # 10
  1. 高级操作
cpp 复制代码
# 追加字符串
APPEND name "李四"  # name 变成 "张三李四"

# 获取字符串长度
STRLEN name

# 覆盖指定位置字符串
SETRANGE name 2 "666"

二、列表(List)

定义:有序、可重复、双向链表,支持左右两边插入 / 弹出。

  1. 添加元素
sql 复制代码
# 1. 左边插入(头插)
LPUSH fruits apple banana

# 2. 右边插入(尾插)
RPUSH fruits orange grape

# 3. 插入到某个元素前/后
LINSERT fruits before "orange" "pear"
  1. 查询元素
sql 复制代码
# 1. 获取全部元素(0=开始,-1=最后)
LRANGE fruits 0 -1

# 2. 获取列表长度
LLEN fruits

# 3. 获取指定下标元素
LINDEX fruits 1
  1. 删除 / 弹出元素
sql 复制代码
# 1. 左边弹出(删除第一个)
LPOP fruits

# 2. 右边弹出(删除最后一个)
RPOP fruits

# 3. 删除指定个数的元素
LREM fruits 2 "apple"  # 删除2个apple

# 4. 保留指定区间,其余删除
LTRIM fruits 0 2
  1. 高级操作
sql 复制代码
# 右边弹出并左边插入到另一个列表
RPOPLPUSH list1 list2

三、哈希(Hash)

定义:key=field-value 结构,适合存对象(用户、商品)。

  1. 添加 / 修改字段
sql 复制代码
# 1. 设置单个字段
HSET user:1001 name "张三" age 20

# 2. 批量设置
HMSET user:1001 phone 13800138000 sex 男
  1. 查询字段
sql 复制代码
# 1. 获取单个字段
HGET user:1001 name

# 2. 批量获取字段
HMGET user:1001 age phone

# 3. 获取所有字段+值
HGETALL user:1001

# 4. 获取所有字段名
HKEYS user:1001

# 5. 获取所有值
HVALS user:1001

# 6. 获取字段数量
HLEN user:1001
  1. 删除 / 判断
sql 复制代码
# 1. 删除指定字段
HDEL user:1001 sex

# 2. 判断字段是否存在
HEXISTS user:1001 name

# 3. 字段数值自增
HINCRBY user:1001 age 1

四、集合(Set)

定义:无序、不可重复、自动去重,支持交集 / 并集 / 差集。

  1. 添加 / 删除
sql 复制代码
# 1. 添加元素
SADD tags java python redis

# 2. 删除元素
SREM tags java

# 3. 随机弹出一个元素
SPOP tags
  1. 查询元素
cs 复制代码
# 1. 查看所有元素
SMEMBERS tags

# 2. 判断元素是否存在
SISMEMBER tags python

# 3. 集合大小
SCARD tags

# 4. 随机获取元素(不删除)
SRANDMEMBER tags 2
  1. 集合运算(最强大功能)
cpp 复制代码
SADD set1 a b c
SADD set2 c d e

# 1. 交集(共同拥有)
SINTER set1 set2  # c

# 2. 并集(合并去重)
SUNION set1 set2  # a b c d e

# 3. 差集(set1有,set2没有)
SDIFF set1 set2  # a b

五、有序集合(Sorted Set / ZSet)

定义:按 score 自动排序、不重复,专门做排行榜。

  1. 添加 / 修改
cs 复制代码
# 1. 添加元素(score 在前,value 在后)
ZADD rank 95 "张三" 98 "李四" 88 "王五"

# 2. 修改分数
ZINCRBY rank 2 "张三"  # 95+2=97
  1. 排序查询(核心)
cpp 复制代码
# 1. 正序查询(分数从低到高)
ZRANGE rank 0 -1 WITHSCORES

# 2. 倒序查询(分数从高到低,排行榜专用)
ZREVRANGE rank 0 -1 WITHSCORES

# 3. 获取元素分数
ZSCORE rank "李四"

# 4. 获取元素排名(正序/倒序)
ZRANK rank "张三"   # 正序排名
ZREVRANK rank "张三" # 倒序排名
  1. 统计 / 删除
cpp 复制代码
# 1. 删除元素
ZREM rank "王五"

# 2. 统计分数区间数量
ZCOUNT rank 90 100

# 3. 删除指定排名区间元素
ZREMRANGEBYRANK rank 0 1

# 4. 删除指定分数区间元素
ZREMRANGEBYSCORE rank 80 90

3.redis的三种特殊类型

一、Geospatial(地理空间类型)

  1. 核心定义

专门用来存储地理位置信息 (经纬度),并支持计算两地距离、查找指定范围内的地点等地理计算。

底层原理:本质是用 ZSet(有序集合) 实现的,把经纬度编码成一个分数存储。

  1. 核心命令
sql 复制代码
# 1. 添加地理位置(经度、纬度、名称)
GEOADD key 经度 纬度 名称 [经度 纬度 名称 ...]

# 示例:添加北京、上海、广州的坐标
GEOADD city 116.40 39.90 beijing 121.47 31.23 shanghai 113.27 23.13 guangzhou

# 2. 计算两个地点之间的距离(单位:m/km/mi/ft)
GEODIST key 名称1 名称2 [单位]

# 示例:计算北京到上海的距离(公里)
GEODIST city beijing shanghai km

# 3. 查找以某个坐标为中心,指定半径内的所有地点
GEORADIUS key 经度 纬度 半径 单位 [WITHDIST] [WITHCOORD]

# 示例:查找以北京为中心,1000公里内的城市
GEORADIUS city 116.40 39.90 1000 km

# 4. 获取指定地点的经纬度
GEOPOS key 名称
  1. 适用场景
  • 附近的人、附近的门店(美团 / 饿了么、微信附近的人)

  • 打车软件计算司机与乘客距离

  • 地理围栏、位置推荐


二、HyperLogLog(基数统计类型)

  1. 核心定义

专门用来做基数统计 (统计一组数据中不重复元素的个数 ),占用内存极小(仅 12KB),支持海量数据统计。

特点:有极小误差(约 0.81%),不存储原始数据,只存统计结构,适合不需要精确值的场景。

  1. 核心命令
sql 复制代码
# 1. 添加元素
PFADD key 元素1 元素2 ...

# 示例:统计网站UV(添加用户ID)
PFADD uv:20260331 user1 user2 user3 user1

# 2. 统计基数(不重复元素数量)
PFCOUNT key

# 示例:查询今日独立访客数
PFCOUNT uv:20260331

# 3. 合并多个HyperLogLog(统计多天总UV)
PFMERGE destKey sourceKey1 sourceKey2 ...

# 示例:合并3天UV
PFMERGE uv:total uv:20260330 uv:20260331
  1. 适用场景
  • 统计网站 / APP 独立访客(UV)

  • 统计页面日活、月活

  • 海量数据去重计数(不要求 100% 精确)


三、Bitmap(位图类型)

  1. 核心定义

本质是String 类型的特殊用法 ,把字符串当成二进制位(bit)数组 来用,极致节省内存

1 个 Byte = 8bit,1MB 可以存储 838 万 个 bit 位 ,适合存储二状态数据(是 / 否、0/1)。

  1. 核心命令
sql 复制代码
# 1. 设置指定位置的bit值(0或1)
SETBIT key offset value

# 示例:记录用户1001今日签到(offset=用户ID,1=已签到)
SETBIT sign:20260331 1001 1

# 2. 获取指定位置的bit值
GETBIT key offset

# 示例:查询用户1001是否签到
GETBIT sign:20260331 1001

# 3. 统计key中bit为1的数量
BITCOUNT key [start end]

# 示例:统计今日总签到人数
BITCOUNT sign:20260331
  1. 适用场景
  • 用户签到、打卡统计

  • 用户是否在线、是否已读

  • 黑名单 / 白名单快速判断

  • 海量用户状态标记

4.事务

一、Redis 事务核心特性

一次性,顺序性,排他性,执行一系列的命令!

  • MySQL 中的事务,要么同时成功,要么同时失败,必须保证原子性!

  • Redis 单条命令是保证原子性的,但是 Redis 的事务不保证原子性!

  • Redis 事务是没有隔离级别的概念


1、Redis 的事务机制

事务使用过程

Redis 的事务使用分为三步:

  • 开启事务 -- multi

  • 命令入队 -- ......

  • 执行事务 -- exec

所有的命令在事务中,并没有直接被执行!只有发起执行命令的时候才会执行!


正常执行事务

sql 复制代码
127.0.0.1:6379> multi        # 开启事务
OK
127.0.0.1:6379> set k1 v1    # 命令入队
QUEUED
127.0.0.1:6379> set k2 v2    # 命令入队
QUEUED
127.0.0.1:6379> get k2       # 命令入队
QUEUED
127.0.0.1:6379> set k3 v3    # 命令入队
QUEUED
127.0.0.1:6379> exec         # 执行事务
1) OK
2) OK
3) "v2"
4) OK

放弃事务 discard

sql 复制代码
127.0.0.1:6379> multi
OK
127.0.0.1:6379> set k1 v1
QUEUED
127.0.0.1:6379> set k2 v2
QUEUED
127.0.0.1:6379> set k4 v4
QUEUED
127.0.0.1:6379> discard      # 放弃事务
OK
127.0.0.1:6379> get k4       # 事务队列中的命令都不会执行
(nil)

编译型异常(命令有错),事务中所有的命令都不会被执行

sql 复制代码
127.0.0.1:6379> keys *
(empty array)
127.0.0.1:6379> multi
OK
127.0.0.1:6379> set k1 v1
QUEUED
127.0.0.1:6379> getset k2    # 命令不正确
(error) ERR wrong number of arguments for 'getset' command
127.0.0.1:6379> set k3 v3
QUEUED
127.0.0.1:6379> exec         # 执行事务时,其他命令也不会执行
(error) EXECABORT Transaction discarded because of previous errors.
127.0.0.1:6379> get k1
(nil)
127.0.0.1:6379> get k3
(nil)

执行时异常,如果事务队列中存在语法性错误,执行命令的时候,其他命令可以正常执行,错误命令抛出异常

sql 复制代码
127.0.0.1:6379> keys *
(empty array)
127.0.0.1:6379> set k1 "v1"
OK
127.0.0.1:6379> multi
OK
127.0.0.1:6379> incr k1      # 会执行的时候失败
QUEUED
127.0.0.1:6379> set k2 v2
QUEUED
127.0.0.1:6379> set k3 v3
QUEUED
127.0.0.1:6379> get k2
QUEUED
127.0.0.1:6379> exec         # 执行事务是,第一个命令执行出错,其他命令依旧会执行
1) (error) ERR value is not an integer or out of range
2) OK
3) OK
4) "v2"
127.0.0.1:6379> get k2
"v2"

2、Redis 的乐观锁 Watch

悲观锁 & 乐观锁

  • 悲观锁:很悲观,认为什么时候都会出问题,无论做什么都会加锁!但是影响效率!

  • 乐观锁:很乐观,认为什么时候都不会出问题,所以不会加锁!更新数据时去判断一下,在此期间是否有人修改过这个数据!MySQL 的 version 的使用:先获取 version,更新数据时比较 version,看 version 是否被修改


Redis 的监视测试

1、正常执行成功!

sql 复制代码
127.0.0.1:6379> set money 100
OK
127.0.0.1:6379> set out 0
OK
127.0.0.1:6379> watch money    #监视money对象
OK
127.0.0.1:6379> multi           #事务正常结束,数据期间没有发生变动,这个时候就正常执行成功
OK
127.0.0.1:6379> decrby money 20
QUEUED
127.0.0.1:6379> incrby out 20
QUEUED
127.0.0.1:6379> exec
1) (integer) 80
2) (integer) 20

2、多线程修改值,使用 watch 可以当做 Redis 的乐观锁操作!

A 客户端执行命令集合

sql 复制代码
127.0.0.1:6379> get money
"80"
127.0.0.1:6379> set money 1000
OK

B 客户端执行命令集合

sql 复制代码
127.0.0.1:6379> watch money
OK
127.0.0.1:6379> multi
OK
127.0.0.1:6379> DECRBY money 10
QUEUED
127.0.0.1:6379> INCRBY out 10
QUEUED
127.0.0.1:6379> exec             # 在该命令执行之前,A客户端执行了set命令修改了money的值,就会导致事务执行失败
(nil)

watch 监视下的事务执行失败后,可以 unwatch 解锁,在重新开始监视

sql 复制代码
127.0.0.1:6379> UNWATCH          #事务执行失败,先解锁
OK
127.0.0.1:6379> WATCH money      #获取最新的值,再次监视
OK
127.0.0.1:6379> multi
OK
127.0.0.1:6379> DECRBY money 10
QUEUED
127.0.0.1:6379> INCRBY out 10
QUEUED
127.0.0.1:6379> exec             # 比对监视的值是否发生变化,如果没有变化,可以执行成功,如果变量被修改了,执行失败
1) (integer) 990
2) (integer) 30
相关推荐
夕除2 小时前
Mysql--14
数据库·mysql
123过去2 小时前
sucrack使用教程
linux·网络·测试工具·安全
014-code2 小时前
Java Optional 那些被忽略的用法
java·数据库·javase
码云数智-园园2 小时前
关系型与非关系型数据库:核心区别与业务场景解析
数据库·oracle
弘毅 失败的 mian2 小时前
Linux 进程属性详解
linux·运维·服务器·经验分享·笔记
茉莉玫瑰花茶2 小时前
Redis 持久化
redis·git·github
Javatutouhouduan2 小时前
SQL优化从入门到精通!
java·数据库·mysql·sql优化·java面试·后端开发·java程序员
jnrjian2 小时前
restore archivelog RAC thread from sequence logseq
服务器·数据库
小草儿7992 小时前
PG18之插件使用大全(简单用例)
数据库