【Redis入门】一篇详解Redis五大数据结构

前言

什么是Redis?

Redis(Remote Dictionary Service,远程字典服务)是一个开源的内存数据库,也是目前最流行的KV(Key-Value)数据库之一。

它与传统数据库最大的区别在于:数据存储在内存中 ,而不是磁盘上。这使得Redis的读写速度极快,官方宣传比磁盘快约10万倍

举一个直观的例子:

  • 从内存读取数据:微秒级(μs)
  • 从磁盘读取数据:毫秒级(ms)

差了整整1000倍,实际场景中差距可能更大。

Redis和数据结构数据库

很多人把Redis叫做"KV数据库",但这个说法不够准确。Redis的全称是Remote Dictionary Service(远程字典服务),它的value支持丰富的数据结构,因此更准确地说,Redis是一个数据结构数据库

KV数据库和数据结构数据库的区别:

类型 操作方式 示例
KV数据库 通过key找到整个value 简单键值对,一个key对应一个值
数据结构数据库 通过key找到value,再通过内部结构操作 key对应一个list/hash/set等复杂结构

Redis的应用定位

Redis通常不作为主力数据库使用,而是作为缓存层配合MySQL等磁盘数据库一起使用:

复制代码
用户请求 → Redis缓存(命中) → 直接返回
 ↓(未命中)
 → MySQL磁盘数据库 → 写入Redis缓存 → 返回

这种架构被称为Cache-Aside模式,是Redis最经典的使用方式。


一、Redis的通信模式

请求-响应模式

Redis采用请求-响应模式工作:

  1. 建立连接:客户端先与Redis服务器建立TCP连接
  2. 发送指令:客户端发送操作指令(指令中包含要操作的key)
  3. 等待响应:Redis执行指令后返回结果
  4. 处理结果:客户端解析结果

注意:Redis是单线程执行的,但基于IO多路复用(Linux的epoll/kqueue),可以同时处理大量并发连接。这意味着Redis不会出现线程安全问题。

启动Redis

bash 复制代码
redis-server   # 启动Redis服务器(默认端口6379)
redis-cli      # 启动Redis客户端(连接本地6379)

连接远程Redis:

bash 复制代码
redis-cli -h 192.168.1.100 -p 6379

基本命令练习

bash 复制代码
PING                    # 测试连接,返回PONG
PING "Hello Redis"      # 返回 "Hello Redis"

二、Redis数据类型全景图

在深入学习之前,先来看一下Redis的整体数据结构体系:

复制代码
Redis数据类型
├── String(字符串)
├── List(列表)
├── Hash(哈希)
├── Set(集合)
├── ZSet(有序集合)
└── 特殊类型
    ├── Bitmaps(位图)
    ├── HyperLogLog(基数统计)
    ├── Geospatial(地理位置)
    └── Stream(流)

本文重点介绍前五种基本数据类型,它们是Redis的骨架。

如何选择数据结构?

这个问题几乎是Redis面试必问题。简单总结:

需求 推荐类型
存储单个字符串/数字 String
存储有序列表(队列、栈) List
存储对象/属性变更频繁的数据 Hash
去重、集合运算(好友关系) Set
排序+去重(排行榜) ZSet

三、String(字符串)

3.1 什么是String

String是Redis最基本的数据类型 ,它是安全的二进制字符串

"安全"是什么意思?

在C语言中,字符串以\0作为结束标志。如果字符串内容本身包含\0,程序可能会被截断。Redis的String用长度字段来描述字符串,而不是依赖特定分隔符,所以可以存储任何二进制数据(图片、视频、音频、压缩包等)。

String的最大长度是512MB

3.2 底层实现原理

Redis的String底层实现叫做SDS(Simple Dynamic String,简单动态字符串),它比C语言的字符串更高效和安全。

SDS的结构(Go语言风格的伪代码):

c 复制代码
struct sdshdr {
    int len;      // 已使用长度
    int free;     // 剩余可用长度
    char[] buf;   // 实际存储字符串的数组
};

这样做有什么好处?

  1. O(1)获取字符串长度 :直接读len字段,不用遍历计数
  2. 防止缓冲区溢出:扩容前先检查空间,不够就自动扩展
  3. 减少内存重分配 :通过free字段记录剩余空间,避免频繁扩容

3.3 扩容策略

Redis的String扩容遵循以下规则:

复制代码
当字符串长度 < 1MB时
    → 扩容策略:空间翻倍(free = len)

当字符串长度 >= 1MB时
    → 扩容策略:每次只增加1MB(free = 1MB)

这样设计是为了平衡内存使用和扩容频率。

3.4 常用命令详解

bash 复制代码
# 基本操作
SET key value              # 设置单个key-value
GET key                    # 获取value
MGET key1 key2 key3       # 批量获取
MSET key1 value1 key2 value2  # 批量设置
DEL key                    # 删除key-value

# 数字操作(Redis会自动识别数字字符串并支持自增)
INCR key                   # value + 1(原子操作)
INCRBY key 10             # value + 10
DECR key                   # value - 1
DECRBY key 5              # value - 5
INCRBYFLOAT key 3.5       # 浮点数自增

# 原子操作-setnx
SETNX key value           # 仅当key不存在时设置(分布式锁常用)
SETEX key 10 value        # 设置值并指定过期时间(10秒)
PSETEX key 1000 value     # 设置值并指定过期时间(毫秒)

# 截取和替换
APPEND key "world"        # 字符串追加
SUBSTR key 0 4            # 截取子串(返回"hello")
STRLEN key                # 获取字符串长度

# 位图操作(进阶)
SETBIT key offset value   # 设置某位的值(0或1)
GETBIT key offset         # 获取某位的值
BITCOUNT key              # 统计位为1的数量
BITOP AND destkey key1 key2  # 位运算AND

3.5 String的应用场景

场景1:分布式锁

分布式锁是String最经典的应用之一。利用SETNX命令的原子性:

bash 复制代码
# 加锁
SETNX lock:order:12345 "locked"
EXPIRE lock:order:12345 30   # 锁的过期时间30秒

# 更好的方式是原子操作(Redis 2.6.12+)
SET lock:order:12345 "locked" NX EX 30

# 解锁
DEL lock:order:12345

⚠️ 注意:解锁前应该检查value是否是自己设置的,防止误删别人的锁。更完善的做法是使用Lua脚本或Redisson框架。

场景2:计数器
bash 复制代码
# 文章阅读量
INCR article:1001:reads
INCRBY article:1001:reads 10

# 点赞数
INCR like:post:12345
DECR like:post:12345

为什么要用Redis做计数器而不是直接更新数据库?

  • 性能:Redis操作在内存中完成,比磁盘快10万倍
  • 并发:Redis单线程天然保证原子性,高并发下不会出错
  • 抗压:瞬时大量请求先在Redis累加,再异步落库,保护数据库
场景3:Session共享

传统Web服务如果有多个实例,Session存在单机内存中,用户每次访问可能负载均衡到不同机器,导致Session丢失。

bash 复制代码
# 存储用户登录信息
SET session:user:10001 '{"userId":10001,"username":"mark","loginTime":"2024-01-01"}'
EXPIRE session:user:10001 3600  # 1小时后过期
场景4:缓存JSON对象
bash 复制代码
# 存一个用户对象
SET user:10001:info '{"name":"mark","age":30,"city":"nanjing"}'

# 取出来使用
GET user:10001:info

⚠️ 什么时候用String存JSON,什么时候用Hash?

用String的场景

  • 对象属性几乎不变化
  • 每次都是整体读取、整体更新
  • 不关心某个字段的独立性

用Hash的场景(推荐大多数情况):

  • 属性经常变化(单独改一个字段)
  • 需要按字段查询
  • 需要对单个字段做自增等操作

四、List(列表)

4.1 什么是List

Redis的List是双向链表结构。这意味着:

  • 头尾操作 (LPUSH、RPUSH、LPOP、RPOP)时间复杂度是 O(1)
  • 中间元素查找 时间复杂度是 O(n)
  • 索引访问 (通过下标访问)时间复杂度是 O(n)

4.2 链表结构示意

复制代码
LPUSH                                      RPUSH
  ↓                                         ↓
[head] ←→ [node1] ←→ [node2] ←→ [node3] ←→ [tail]

4.3 常用命令详解

bash 复制代码
# 插入操作
LPUSH key element1 element2 element3   # 从左边插入(头插)
RPUSH key element1 element2 element3   # 从右边插入(尾插)

# 弹出操作
LPOP key                               # 从左边弹出(头删)
RPOP key                               # 从右边弹出(尾删)

# 范围查询
LRANGE key 0 -1                        # 获取所有元素
LRANGE key 0 4                         # 获取前5个元素
LRANGE key -3 -1                       # 获取最后3个元素

# 长度
LLEN key                               # 获取列表长度

# 删除
LREM key count value                   # 删除count个value(count>0从头删,<0从尾删,=0删所有)
LTRIM key 0 4                          # 只保留索引0-4的元素(常用于截断)

# 阻塞操作
BRPOP key timeout                      # 阻塞等待从右边弹出(队列空时等待)
BLPOP key timeout                      # 阻塞等待从左边弹出

# 高级操作
RPOPLPUSH source destination           # 从source弹出尾元素,插入destination头部
BRPOPLPUSH source destination timeout  # 阻塞版本
LINDEX key index                       # 按索引获取元素
LSET key index value                   # 按索引设置元素
LINSERT key BEFORE|AFTER pivot value   # 在pivot前后插入

4.4 List的实现细节

Redis 3.2之前使用**ziplist(压缩列表)linkedlist(双向链表)**两种实现:

  • 元素少且短时用ziplist(节省内存)
  • 元素多或长度大时用linkedlist

Redis 3.2之后统一使用quicklist结构:

  • quicklist = 多个ziplist拼接而成的双向链表
  • 兼顾内存效率和操作性能

4.5 应用场景

场景1:栈(Stack)

特性:先进后出(Last In First Out)

bash 复制代码
LPUSH stack:data 1 2 3 4 5
# 链表:[5, 4, 3, 2, 1]
LPOP stack:data  # 弹出5
LPOP stack:data  # 弹出4
场景2:队列(Queue)

特性:先进先出(First In First Out)

bash 复制代码
LPUSH queue:task task1 task2 task3
# 链表:[task3, task2, task1]
RPOP queue:task  # 弹出task1(先入先出)
场景3:阻塞队列
bash 复制代码
# 客户端A(消费者)- 阻塞等待消息
BRPOP queue:message 0  # 0表示无限等待

# 客户端B(生产者)- 发送消息
LPUSH queue:message "hello"

BRPOP和BLPOP会阻塞等待,直到队列中有元素可弹出。新版本支持多队列阻塞:BRPOP queue1 queue2 queue3 0

场景4:异步消息队列
bash 复制代码
# 生产者:不断发送消息
LPUSH queue:job job1 job2 job3 job4 job5

# 消费者:取出后截断,只保留最新5条
LPOP queue:job
LTRIM queue:job 0 4

⚠️ 这种方式不够优雅,实际生产环境推荐使用Redis Stream(Redis 5.0+)

场景5:朋友圈说说列表
bash 复制代码
# 用户发了一条新说说,插入时间线头部
LPUSH user:10001:posts "post:20001"
LPUSH user:10001:posts "post:20002"

# 获取前10条说说
LRANGE user:10001:posts 0 9

五、Hash(哈希)

5.1 什么是Hash

Hash(哈希)类型是Redis中用来描述对象属性 的数据结构。它特别适合存储属性经常变化的对象。

Hash的key-value结构:

  • key:键名

  • field:字段(相当于对象中的属性名)

  • value:字段对应的值

    key (哈希键) field (字段) value (值)
    user:10001:info → name = "mark"
    → age = 30
    → height = 175

5.2 为什么不用String存对象?

先看看String存对象的痛点:

bash 复制代码
# 用String存用户对象
SET user:10001 '{"name":"mark","age":30}'

# 现在要把age改成31
GET user:10001           # 取出完整的JSON字符串
# 解码 → 修改age字段 → 重新编码
SET user:10001 '{"name":"mark","age":31}'  # 再存回去

问题:

  1. 步骤繁琐:需要先GET → 解码 → 修改 → 编码 → SET
  2. 并发问题:两个请求同时修改,可能产生覆盖
  3. 资源浪费:每次都要操作整个对象,哪怕只改一个字段

用Hash就简单多了:

bash 复制代码
HMSET user:10001 name "mark" age 30 height 175
HINCRBY user:10001 age 1   # 直接对age字段+1,非常高效

5.3 常用命令详解

bash 复制代码
# 基本操作
HSET key field value               # 设置单个字段
HGET key field                     # 获取单个字段
HMSET key field1 value1 field2 value2  # 批量设置字段
HMGET key field1 field2            # 批量获取字段
HGETALL key                        # 获取所有字段和值
HDEL key field1 field2             # 删除字段
HLEN key                           # 获取字段数量

# 判断存在性
HEXISTS key field                  # 判断字段是否存在(返回1或0)

# 自增自减
HINCRBY key field 1                # 字段值+1(必须是整数)
HINCRBYFLOAT key field 0.5         # 字段值+0.5(可以是浮点数)

# 其他操作
HKEYS key                          # 获取所有字段名
HVALS key                          # 获取所有值

5.4 Hash的底层实现

Redis的Hash有两种底层实现:

  1. ziplist(压缩列表):当hash的字段数量少、value长度短时使用,节省内存
  2. hashtable(哈希表):当hash的字段数量多或value长度大时自动转换

配置参数:

复制代码
hash-max-ziplist-entries 512  # 字段数量超过512时转换为hashtable
hash-max-ziplist-value 64     # 单个value超过64字节时转换

5.5 Hash的应用场景

场景1:存储对象属性

这是Hash最经典的应用,几乎所有Redis入门教程都会以此为例:

bash 复制代码
# 存储文章信息
HSET article:1001 title "Redis入门教程" author "洛水水" views 0

# 文章阅读量+1
HINCRBY article:1001 views 1

# 获取文章信息
HGET article:1001 title
HGET article:1001 views
场景2:热点数据缓存
bash 复制代码
# 缓存商品信息(热门商品会被频繁访问)
HSET product:10001 name "iPhone15" price 5999 stock 100
HSET product:10001 color "蓝色" memory "256G"

# 前端查询商品
HGET product:10001 price

为什么不用String存商品?

因为商品可能有10+个属性,用Hash可以只改某一个属性,不影响其他属性。

场景3:记录实时数据
bash 复制代码
# 记录朋友圈点赞数、评论数、转发数
HSET moments:10001 likes 100 comments 20 forwards 5

# 用户点赞,点赞数+1
HINCRBY moments:10001 likes 1

# 用户取消点赞,点赞数-1
HINCRBY moments:10001 likes -1

六、Set(集合)

6.1 什么是Set

Set是无序且不重复的集合。

特性:

  • 无序:元素没有顺序,插入顺序和存储顺序无关
  • 唯一:同一个集合内不会有重复元素
  • 支持交、并、差集运算

6.2 常用命令详解

bash 复制代码
# 基本操作
SADD key member1 member2 member3     # 添加元素(重复元素自动忽略)
SREM key member1 member2           # 删除元素
SMEMBERS key                       # 获取所有元素
SCARD key                          # 获取元素数量(集合长度)
SISMEMBER key member               # 判断元素是否存在(返回1或0)

# 随机操作
SRANDMEMBER key count              # 随机获取count个元素(不删除)
SPOP key count                     # 随机弹出count个元素(会删除)

# 集合运算
SDIFF key1 key2                    # 差集(key1有、key2没有的)
SDIFFSTORE destkey key1 key2       # 差集并存储到destkey
SINTER key1 key2                   # 交集(两者都有的)
SINTERSTORE destkey key1 key2      # 交集并存储
SUNION key1 key2                   # 并集(合并所有)
SUNIONSTORE destkey key1 key2      # 并集并存储

# 移动操作
SMOVE source destination member    # 将元素从source移动到destination

6.3 Set的应用场景

场景1:微信朋友圈点赞用户列表(去重)
bash 复制代码
# 用户10001点赞了说说12345
SADD moments:12345:likes 10001
SADD moments:12345:likes 10002
SADD moments:12345:likes 10001  # 重复点赞,自动忽略

# 检查用户是否已点赞
SISMEMBER moments:12345:likes 10001  # 返回1(已点赞)

# 取消点赞
SREM moments:12345:likes 10001

# 统计点赞数
SCARD moments:12345:likes
场景2:微信好友关系(交、并、差集)
bash 复制代码
# 好友列表
SADD user:10001:friends 10002 10003 10004 10005
SADD user:10006:friends 10003 10004 10007 10008

# 共同好友(交集)
SINTER user:10001:friends user:10006:friends
# 结果:10003, 10004

# 我有但他没有的好友(差集)
SDIFF user:10001:friends user:10006:friends
# 结果:10002, 10005

# 可能认识的人(对方好友 - 已有好友 = 差集)
SDIFF user:10006:friends user:10001:friends
# 结果:10007, 10008

# 合并所有好友(并集)
SUNION user:10001:friends user:10006:friends
# 结果:10002, 10003, 10004, 10005, 10007, 10008
场景3:抽奖程序(随机抽取)
bash 复制代码
# 参与抽奖的用户
SADD lottery:20240101 10001 10002 10003 10004 10005 10006 10007

# 抽取3个中奖者(不重复)
SRANDMEMBER lottery:20240101 3
# 结果:[10003, 10001, 10006](随机)

# 如果需要"抽完不再放回"
SPOP lottery:20240101 3
场景4:标签系统
bash 复制代码
# 给文章打标签
SADD article:1001:tags "Redis" "数据库" "后端"
SADD article:1002:tags "MySQL" "数据库" "后端"
SADD article:1003:tags "Redis" "缓存" "后端"

# 找出同时打了"Redis"和"后端"标签的文章(需要遍历,但思路类似)
# 实际场景可以用Set存储标签下的文章ID列表
SADD tag:Redis articles 1001 1003
SADD tag:后端 articles 1001 1002 1003
SINTER tag:Redis:articles tag:后端:articles

七、ZSet(有序集合)

7.1 什么是ZSet

ZSet(有序集合)是Redis中最复杂的数据结构。

它有两个关键字段:

  • member(成员):元素的值,用于唯一标识
  • score(分数):用于排序,可以是浮点数

特点:

  • 唯一性:同一个ZSet中,member唯一(和Set一样)
  • 有序性:元素按score从小到大排序(可重复)
  • 性能高:score排序基于**跳表(Skip List)**实现,查询/插入/删除都是O(log n)

7.2 为什么用跳表而不是红黑树?

数据结构 查找 插入 删除 范围查找
红黑树 O(log n) O(log n) O(log n) O(log n + k)
跳表 O(log n) O(log n) O(log n) O(log n + k)

跳表的优势:

  1. 实现更简单:比红黑树容易理解和实现
  2. 占用内存更少:不需要存储红黑树那样的平衡因子
  3. 范围查询更方便:跳表的底层是链表,范围遍历更自然

7.3 常用命令详解

bash 复制代码
# 基本操作
ZADD key score1 member1 score2 member2  # 添加元素(带分数)
ZSCORE key member                        # 获取元素的分数
ZRANGE key 0 -1                          # 按分数升序获取所有元素
ZREVRANGE key 0 -1                       # 按分数降序获取所有元素
ZREVRANGE key 0 4 WITHSCORES             # 获取前5名(带分数)

# 排名相关
ZRANK key member                         # 获取元素的排名(升序,0开始)
ZREVRANK key member                      # 获取元素的排名(降序,0开始)

# 删除操作
ZREM key member1 member2                 # 删除元素
ZREMRANGEBYRANK key 0 4                  # 删除排名0-4的元素(升序)
ZREMRANGEBYSCORE key min max             # 删除分数范围内的元素

# 数量统计
ZCARD key                                # 获取元素数量
ZCOUNT key min max                        # 统计分数范围内的元素数量

# 高级操作
ZINCRBY key increment member             # 给元素的分数加increment
ZRANGEBYSCORE key min max                # 按分数范围获取元素
ZSCAN key cursor [MATCH pattern] [COUNT count]  # 渐进式遍历

7.4 ZSet的应用场景

场景1:排行榜

这是ZSet最经典的应用场景。

bash 复制代码
# 游戏战绩排行
ZADD game:1001:scores 9500 "user:10001"
ZADD game:1001:scores 8700 "user:10002"
ZADD game:1001:scores 10000 "user:10003"

# 获取前3名
ZREVRANGE game:1001:scores 0 2 WITHSCORES
# 结果:user:10003 10000, user:10001 9500, user:10002 8700

# 获取user:10001的排名
ZREVRANK game:1001:scores user:10001
# 结果:1(第二名)

# user:10001击败了对手,分数+500
ZINCRBY game:1001:scores 500 user:10001

# 实时查看自己的排名和分数
ZSCORE game:1001:scores user:10001
场景2:微信朋友圈评论列表(按时间排序+去重)
bash 复制代码
# 用户评论,时间戳作为score
ZADD comments:post:12345 1704200000 "comment:50001"
ZADD comments:post:12345 1704200500 "comment:50002"
ZADD comments:post:12345 1704201000 "comment:50003"

# 获取前10条评论(按时间升序)
ZRANGE comments:post:12345 0 9 WITHSCORES

# 获取最新评论(按时间降序)
ZREVRANGE comments:post:12345 0 9 WITHSCORES

# 删除评论
ZREM comments:post:12345 comment:50002
场景3:热搜排行榜
bash 复制代码
# 用户搜索了"Redis教程"
ZINCRBY hot:search 1 "Redis教程"
ZINCRBY hot:search 1 "Redis教程"
ZINCRBY hot:search 1 "MySQL优化"

# 获取当前热搜榜TOP10
ZREVRANGE hot:search 0 9 WITHSCORES
场景4:商品过滤与排序
bash 复制代码
# 存储商品价格作为score
ZADD products:electronics 2999 "iPhone15"
ZADD products:electronics 4999 "iPhone15 Pro"
ZADD products:electronics 5999 "iPhone15 Pro Max"

# 价格从低到高排序
ZRANGE products:electronics 0 -1 WITHSCORES

# 价格从高到低排序
ZREVRANGE products:electronics 0 -1 WITHSCORES

# 筛选1000-4000元的商品
ZRANGEBYSCORE products:electronics 1000 4000

八、数据结构的选择决策树

复制代码
需求场景
│
├─ 需要存储单个值(计数器、字符串)?
│   └─ YES → String
│
├─ 需要保证值的唯一性,且需要集合运算(交并差集)?
│   └─ YES → Set
│
├─ 需要排序(排行榜、热度排序、时间排序)?
│   └─ YES → ZSet
│
├─ 需要频繁修改"对象的某个属性"?
│   └─ YES → Hash
│
├─ 需要存储有序列表(栈、队列、消息队列)?
│   └─ YES → List
│
└─ 其他情况 → String(简单粗暴)

九、Key的规范化设计

Redis的key设计虽然灵活,但有一些最佳实践:

命名规范

bash 复制代码
# 推荐:用冒号:分隔层级
user:10001:info              # 用户基本信息
user:10001:friends           # 用户好友列表
article:1001:comments        # 文章评论

# 不推荐:全部写在一起
user_10001_info              # 难以区分层级
userinfo10001                 # 难以解析

为什么要用:分隔?

  1. 语义清晰:一看就知道是用户ID=10001的信息
  2. 便于管理 :图形化工具(如Redis Desktop Manager、Another Redis Desktop Manager)会按:层级展示
  3. 支持通配符查询KEYS user:10001:* 可以列出某用户的所有key

常见前缀约定

bash 复制代码
# 用户相关
user:{userId}:info              # 用户信息
user:{userId}:friends           # 好友列表
user:{userId}:followers         # 粉丝列表
user:{userId}:articles          # 用户文章

# 业务相关
article:{articleId}:info         # 文章信息
article:{articleId}:comments     # 文章评论
article:{articleId}:likes        # 文章点赞

# 排行榜
rank:{type}:{date}              # 某日排行
hot:search                      # 搜索热度

# 缓存
cache:{entity}:{id}             # 缓存实体
session:{sessionId}            # 会话信息

十、五大数据结构去重能力对比

数据结构 去重方式 说明
String key整体唯一 相同的key会覆盖
Hash field唯一 相同key+field会覆盖
List 不去重 允许重复元素
Set member唯一 相同的member只保留一个
ZSet member唯一 相同的member只保留一个

总结

数据结构 特性 典型应用
String 简单键值对、二进制安全、512MB 缓存、计数器、分布式锁、Session
List 双向链表、有序、头尾O(1) 栈、队列、消息队列、时间线
Hash 键-字段-值、属性操作 对象存储、热点缓存
Set 无序、唯一、集合运算 标签系统、好友关系、去重
ZSet 有序、唯一、跳表实现 排行榜、评论排序、热度排行

核心原则:根据实际需求选择最合适的数据结构,而不是"什么场景都只用String"。


根据零声教育教学写作https://github.com/0voice

相关推荐
CoderCodingNo1 小时前
【CSP】CSP-J 2021真题 | 插入排序 luogu-P7910 (适合GESP四-六级及以上考生练习)
数据结构·算法·排序算法
woodykissme1 小时前
日产汽车花键测绘,为什么总踩坑?
数据库·汽车·齿轮·渐开线花键
雨辰AI2 小时前
从 MySQL 迁移至人大金仓 V9 完整改造指南|分页 / 函数 / 语法兼容全部解决
java·开发语言·数据库·后端·mysql·政务
阿维的博客日记2 小时前
介绍一下Redisson的看门狗机制
java·redis·缓存
Chengbei112 小时前
AI大模型网关存在SQL注入、影响版本LiteLLM 1.81.16~1.83.7(CVE-2026-42208)
数据库·人工智能·sql·安全·web安全·网络安全·系统安全
zx2859634002 小时前
Laravel 9.x:全面升级与核心特性
数据库
庞轩px2 小时前
第四篇:多级缓存架构——Caffeine + Redis + MySQL 三级协同
java·redis·mysql·读写分离·caffeine·本地缓存
x***r1512 小时前
Redis-x64-3.2.100安装步骤详解(附Redis服务注册与配置)
redis
努力努力再努力wz2 小时前
【MySQL进阶系列】一文打通事务机制:从锁、Undo Log 到 MVCC 与隔离级别
c语言·数据结构·数据库·c++·mysql·算法·github