首页
学习
活动
专区
圈层
工具
发布
社区首页 >专栏 >明明接了 Redis,重启后会话还是丢了?

明明接了 Redis,重启后会话还是丢了?

作者头像
程序员NEO
发布2026-04-29 19:37:03
发布2026-04-29 19:37:03
1150
举报
你有没有遇到过这种情况:本地调试都正常,一上测试环境,两台服务的登录态就开始“各管各的”。 我第一次碰到时,最离谱的是服务重启后,用户直接被批量踢下线。 这篇文章不讲空话,就按我真实落地顺序,把 Sa-Token 集成 Redis 的关键点和坑一次说透。

先把问题讲透:为什么默认内存模式会出事

Sa-Token 默认把数据放内存,这个设计本身没问题。 它的优点很实在:,而且没有序列化/反序列化损耗。

但到了真实工程环境,两个问题会非常致命:

  1. 1. 服务重启后数据会丢失
  2. 2. 分布式节点之间无法共享会话数据

所以你会看到一个很典型的现象:

  • • 单机开发阶段,体验很好。
  • • 一旦多实例部署,登录态开始“随机异常”。

我后来把会话层切到 Redis,本质上就是把会话从“进程内状态”变成“共享状态”。 这一步做完,重启丢失和多节点不一致才算真正收敛。

第一步:先用最稳的 RedisTemplate 方案

如果你只想快速落地,不想折腾太多实现细节,直接上官方推荐方案就行。

Maven
代码语言:javascript
复制
<!-- Sa-Token 整合 RedisTemplate -->
<dependency>
    <groupId>cn.dev33</groupId>
    <artifactId>sa-token-redis-template</artifactId>
    <version>${sa.top.version}</version>
</dependency>

<!-- 提供 Redis 连接池 -->
<dependency>
    <groupId>org.apache.commons</groupId>
    <artifactId>commons-pool2</artifactId>
</dependency>
Gradle
代码语言:javascript
复制
// Sa-Token 整合 RedisTemplate
implementation 'cn.dev33:sa-token-redis-template:${sa.top.version}'

// 提供 Redis 连接池
implementation 'org.apache.commons:commons-pool2'

这块我个人建议是:先跑通,再优化。 别一上来就追求“最优序列化格式”,先把会话一致性问题解决掉。

第二步:确认 Redis 真连上了(这一步最容易漏)

我踩过的坑是:依赖加了,但环境变量没配全。 结果项目看起来启动正常,实际会话并没有落到 Redis。

代码语言:javascript
复制
spring: 
    # redis配置 
    redis:
        # Redis数据库索引(默认为0)
        database: 1
        # Redis服务器地址
        host: 127.0.0.1
        # Redis服务器连接端口
        port: 6379
        # Redis服务器连接密码(默认为空)
        # password: 
        # 连接超时时间
        timeout: 10s
        lettuce:
            pool:
                # 连接池最大连接数
                max-active: 200
                # 连接池最大阻塞等待时间(使用负值表示没有限制)
                max-wait: -1ms
                # 连接池中的最大空闲连接
                max-idle: 10
                # 连接池中的最小空闲连接
                min-idle: 0
代码语言:javascript
复制
# Redis数据库索引(默认为0)
spring.redis.database=1
# Redis服务器地址
spring.redis.host=127.0.0.1
# Redis服务器连接端口
spring.redis.port=6379
# Redis服务器连接密码(默认为空)
# spring.redis.password=
# 连接超时时间
spring.redis.timeout=10s
# 连接池最大连接数
spring.redis.lettuce.pool.max-active=200
# 连接池最大阻塞等待时间(使用负值表示没有限制)
spring.redis.lettuce.pool.max-wait=-1ms
# 连接池中的最大空闲连接
spring.redis.lettuce.pool.max-idle=10
# 连接池中的最小空闲连接
spring.redis.lettuce.pool.min-idle=0

⚠️ 小提示:如果你是 SpringBoot3.x,前缀要从 spring.redis 改成 spring.data.redis

第三步:理解序列化,不然排障会很痛苦

默认情况下,Redis 里看到的是 JSON 格式。 这没什么问题,但你要知道它背后是两层序列化:

  • String 序列化
  • JSON 序列化

如果你需要换 JSON 框架,可以用这些依赖。

Fastjson
代码语言:javascript
复制
<!-- Sa-Token 整合 Fastjson -->
<dependency>
    <groupId>cn.dev33</groupId>
    <artifactId>sa-token-fastjson</artifactId>
    <version>${sa.top.version}</version>
</dependency>

Gradle 参考:implementation 'cn.dev33:sa-token-fastjson:${sa.top.version}'

Fastjson2
代码语言:javascript
复制
<!-- Sa-Token 整合 Fastjson2 -->
<dependency>
    <groupId>cn.dev33</groupId>
    <artifactId>sa-token-fastjson2</artifactId>
    <version>${sa.top.version}</version>
</dependency>

Gradle 参考:implementation 'cn.dev33:sa-token-fastjson2:${sa.top.version}'

Snack3
代码语言:javascript
复制
<!-- Sa-Token 整合 Snack3 -->
<dependency>
    <groupId>cn.dev33</groupId>
    <artifactId>sa-token-snack3</artifactId>
    <version>${sa.top.version}</version>
</dependency>

Gradle 参考:implementation 'cn.dev33:sa-token-snack3:${sa.top.version}'

第四步:不想走 JSON?直接改 String 序列化

这个场景我也遇到过。 有些老系统有固定编码约束,不想引入 JSON 序列化,就直接切 String 层。

jdk序列化 (base64编码)
代码语言:javascript
复制
// 设置序列化方案: jdk序列化 (base64编码)
@PostConstruct
public void rewriteComponent() {
    SaManager.setSaSerializerTemplate(new SaSerializerTemplateForJdkUseBase64());
}
jdk序列化 (16进制编码)
代码语言:javascript
复制
// 设置序列化方案: jdk序列化 (16进制编码)
@PostConstruct
public void rewriteComponent() {
    SaManager.setSaSerializerTemplate(new SaSerializerTemplateForJdkUseHex());
}
jdk序列化 (ISO-8859-1编码)
代码语言:javascript
复制
// 设置序列化方案: jdk序列化 (ISO-8859-1编码)
@PostConstruct
public void rewriteComponent() {
    SaManager.setSaSerializerTemplate(new SaSerializerTemplateForJdkUseISO_8859_1());
}

💡 实战建议:

  • • 新项目优先默认 JSON,排查成本更低。
  • • 老系统有兼容包袱,再考虑切 JDK 序列化。
  • • 序列化方案一旦定了,尽量别频繁改,不然后续迁移很麻烦。

第五步:几个高频问答,都是线上真问题

1. 集成 Redis 后,需要手动保存数据吗? 不需要,框架自动保存。你上层 API 基本不用改。

2. 只加依赖,不配 Redis 连接可以吗? 不行。必须保证项目初始化出可用 Redis 实例。

3. 版本怎么选? Sa-Token-Redis 集成包版本,尽量和 Sa-Token-Starter 保持一致,不然兼容性问题很隐蔽。

扩展:如果你不是 Redis 体系

Sa-Token 也给了 MongoDB 的集成参考:

  • • 集成 MongoDB 参考一[1]
  • • 集成 MongoDB 参考二[2]

我最后沉淀的一条落地顺序

🚀 真要在项目里稳落地,我建议按这个顺序:

  1. 1. 先用 sa-token-redis-template 跑通全链路。
  2. 2. 验证重启后会话是否保留、双节点是否一致。
  3. 3. 再根据项目历史包袱决定是否换序列化方案。
  4. 4. 最后统一版本并做一次压测和故障演练。

工程里最危险的,不是“不会配 Redis”,而是“以为自己已经配好了 Redis”。

你们项目里,Sa-Token 会话层是直接内存模式,还是已经切到 Redis 了? 如果切过,你踩过最难排查的坑是哪一个?评论区聊聊

本章源码(GitHub): https://github.com/BNTang/Sa-Token-Demo/tree/main/sa-token-demo-redis

引用链接

[1] 集成 MongoDB 参考一: /up/integ-spring-mongod-1 [2] 集成 MongoDB 参考二: /up/integ-spring-mongod-2

如果这篇文章帮到了你,不妨点个分享给同样需要的朋友吧! 你的每一次支持,都是我持续创作的动力!💪

本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2026-03-03,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 程序员NEO 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 先把问题讲透:为什么默认内存模式会出事
  • 第一步:先用最稳的 RedisTemplate 方案
    • Maven
    • Gradle
  • 第二步:确认 Redis 真连上了(这一步最容易漏)
  • 第三步:理解序列化,不然排障会很痛苦
    • Fastjson
    • Fastjson2
    • Snack3
  • 第四步:不想走 JSON?直接改 String 序列化
    • jdk序列化 (base64编码)
    • jdk序列化 (16进制编码)
    • jdk序列化 (ISO-8859-1编码)
  • 第五步:几个高频问答,都是线上真问题
  • 扩展:如果你不是 Redis 体系
  • 我最后沉淀的一条落地顺序
    • 引用链接
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档