sessioncallback 是 spring boot 中 redistemplate 实现事务的唯一可靠方式,通过复用同一 redisconnection 并在 execute() 内部调用 operations.multi() 和 operations.exec() 来模拟原子性,需配合 watch 实现乐观锁,异常时自动丢弃命令队列。

SessionCallback 是唯一可靠的方式
Spring Boot 的 RedisTemplate 默认不支持事务,setEnableTransactionSupport(true) 在 Spring Data Redis 2.0+(尤其是 Lettuce 客户端)中已失效,调用 multi() + exec() 会直接抛出 java.lang.UnsupportedOperationException: Transactions not supported。真正能落地的只有 SessionCallback ——它不是“开启事务”,而是复用底层 RedisConnection,保证所有操作在同一个连接上下文中执行,从而模拟出原子性语义。
必须用 execute(SessionCallback) 而非直接调用 multi/exec
SessionCallback 的核心是把所有命令塞进同一个连接的 pipeline + multi 队列里,靠 Redis 原生的 MULTI/EXEC 机制完成提交。常见错误是:在 callback 外调用 redisTemplate.multi(),或在 callback 里混用 redisTemplate 实例(而非传入的 operations 参数)。
抓取并分析 OpenClaw JSONL 会话日志,重建并回填代理记忆文件。适用于:(1) 模型切换后记忆不完整,(2) 验证记忆覆盖度,(3) 重建丢失记忆,(4) 通过 cron/heartbeat 自动同步每日记忆。支持简单提取及基于 LLM 的叙事摘要,并自动清理敏感信息。
- ✅ 正确写法:只在
execute()内部通过operations调用multi()、opsForValue().set()等,并以operations.exec()结尾 - ❌ 错误写法:
redisTemplate.multi()放在 callback 外;或 callback 里写redisTemplate.opsForValue().set(...) - ⚠️ 注意:callback 返回值必须是
operations.exec()的结果(List<object></object>),否则事务不会提交
watch + SessionCallback 才算真正实现乐观锁
纯 SessionCallback 只保证命令顺序执行,不防并发修改。若需类似数据库 UPDATE WHERE version = ? 的效果,必须配合 watch。但注意:watch 必须在 operations.multi() 之前调用,且 watch 的 key 必须由 operations 实例执行(不能用外部 redisTemplate)。
- ✅ 正确顺序:
operations.watch("stock:1001") → operations.multi() → operations.opsForValue().get("stock:1001") → ... → operations.exec() - ❌ watch 放在 multi 之后无效;watch 用
redisTemplate.watch()会导致连接不一致,watch 失效 - ? exec 返回 null 表示 watch key 被其他客户端修改过,此时整个事务被丢弃,需自行重试逻辑
异常发生时事务自动回滚,但连接不会中断
在 SessionCallback.execute() 中抛出异常(如 RuntimeException),operations.exec() 不会被调用,队列里的命令全部丢弃 —— 这等效于 Redis 的事务回滚。但要注意:
- 连接本身不受影响,后续请求仍可复用该连接
- 不会触发 Spring 的
@Transactional回滚(Redis 事务和 JDBC 事务完全无关) - 如果 callback 中部分命令已执行(比如 watch 前就调用了 set),那些操作无法撤回 —— 所以 watch 和 multi 必须紧邻,中间不要穿插非事务操作
execute() 方法的进出决定,而不是某行 multi() 调用。










