首页/新闻资讯/正文详情

Redis为什么不支持回滚?事务机制、设计取舍与业务补偿全解析

发布时间:2026/9/24 23:18:22 来源:云帆数科 栏目:资讯中心
Redis为什么不支持回滚?事务机制、设计取舍与业务补偿全解析
在做 Redis 技术面试复盘的时候我发现一个很有意思的现象几乎每一篇 Redis 面试题汇总里都有为什么 Redis 不支持回滚这道题但绝大多数人给出的答案都停留在因为 Redis 追求性能这个层面。我第一次被问到这个问题时脑子里蹦出来的也只有这半句话结果面试官追了一句那为什么追求性能就要砍掉回滚MySQL 也有性能压力不照样有回滚机制吗当场卡住。后来我把 Redis 事务的官方文档、源码里事务执行的流程以及作者在社区里的相关讨论都翻了一遍才算把这个问题真正想透。这篇文章就把整条脉络完整捋一遍先看 Redis 事务从开始到结束到底发生了什么再拆两类错误的处理逻辑然后说清楚官方的设计取舍最后落到实际开发里没有回滚时业务怎么保证一致性结尾会给出一套面试现场可以直接用的回答框架。1. 先搞清楚一次 Redis 事务从开始到结束服务器到底做了什么1.1 面试官一提回滚真正想考的是 Redis 事务的错误处理机制要回答为什么 Redis 不支持回滚有个前提必须先立住这个问题的讨论范围是 Redis 的 MULTI...EXEC 事务模型。Redis 里所谓的不支持回滚指的是命令在执行阶段出错时服务器不会像关系型数据库那样把前面已经执行的写操作撤销回来。Redis 对事务的定位和关系型数据库完全不同。关系型数据库里一个事务通常包含多条 SQL涉及多张表、多个索引、各种约束校验事务必须保证这组操作要么全部生效、要么全部不生效。而 Redis 的事务本质上是把一组命令打包通过 EXEC 一次性按顺序交给服务器执行执行过程中不被其他客户端的命令插入。它保证的是这一批命令作为一个整体被执行但不保证每一条命令都成功——这两件事经常被混淆也是理解本题的关键。1.2 四条命令构成的事务骨架Redis 事务相关的命令就四条MULTI、EXEC、DISCARD、WATCH。MULTI标记一个事务块的开始。从 MULTI 之后到 EXEC 之前客户端发送的命令不会立即执行而是进入服务器端的一个队列。EXEC触发事务执行。服务器把队列里的命令按顺序全部执行完然后把结果一次性返回给客户端。DISCARD放弃事务队列。在 EXEC 之前调用清空队列退出事务状态。WATCH乐观锁。在执行 MULTI 之前调用监听一个或多个 key。EXEC 时如果发现被监听的 key 在 WATCH 之后被其他客户端改过整个事务直接不执行。新手特别容易忽略一个点Redis 事务不是先锁定资源再执行的悲观事务而是先登记意图、最后一把梭的乐观模型。它没有关系型数据库里 BEGIN / COMMIT / ROLLBACK 那种一一对应的语义DISCARD 更像算了我不做了而不是把已经做的撤销掉——因为在 DISCARD 的时刻队列里的命令一条都还没执行。1.3 用 redis-cli 实际走一遍三种流程先看正常流程127.0.0.1:6379 MULTI OK 127.0.0.1:6379(TX) SET balance:001 100 QUEUED 127.0.0.1:6379(TX) DECRBY balance:001 30 QUEUED 127.0.0.1:6379(TX) EXEC 1) OK 2) (integer) 70注意中间几条命令的返回都是 QUEUED只有 EXEC 之后才真正执行并返回结果。这个先入队、后执行的设计是理解后面一切问题的基础。再看执行阶段出错的情况127.0.0.1:6379 MULTI OK 127.0.0.1:6379(TX) SET balance:001 abc QUEUED 127.0.0.1:6379(TX) INCR balance:001 QUEUED 127.0.0.1:6379(TX) SET balance:002 200 QUEUED 127.0.0.1:6379(TX) EXEC 1) OK 2) (error) ERR value is not an integer or out of range 3) OKINCR 对字符串 abc 执行失败但后面的 SET balance:002 200 照常执行。这就是不支持回滚最直接的表现执行阶段的错误不会中断整个事务更不会撤销 INCR 之前已经执行的 SET。再看入队阶段出错的情况127.0.0.1:6379 MULTI OK 127.0.0.1:6379(TX) SET balance:001 100 QUEUED 127.0.0.1:6379(TX) SETI balance:001 200 (error) ERR unknown command SETI 127.0.0.1:6379(TX) SET balance:002 200 QUEUED 127.0.0.1:6379(TX) EXEC (error) EXECABORT Transaction discarded because of previous errors.命令名写错这种入队失败结果是整个事务被丢弃EXEC 直接报 EXECABORT。不少人把这条当成Redis 其实也会回滚的证据但这是不对的——出错时队列里的命令一条都还没执行这是取消不是回滚。这两种错误必须分清这也是这道题能不能答好的分水岭。2. 回滚机制在传统数据库里到底做了什么Redis 为什么可以不做2.1 关系型数据库的回滚一套完整的 undo log 机制要理解为什么不支持回滚得先看清楚回滚这件事本身有多重。在 InnoDB 这类存储引擎里事务执行过程中只要某条 SQL 失败或者应用主动 ROLLBACK数据库必须把该事务所有已完成的修改全部撤销更新的行要恢复旧值插入的行要删除删除的行要复原索引要同步调整。为了做到这一点事务在真正修改数据之前会把修改前的映像写入 undo log一旦需要回滚就顺着 undo log 一步一步还原现场。但回滚远不是记个旧值再写回去这么简单。InnoDB 的多版本并发控制MVCC也依赖 undo log事务隔离级别、长事务、大事务的提交与回滚都跟它深度纠缠。回滚本身的可靠性问题同样棘手回滚到一半宕机了怎么办数据页和索引页不一致怎么处理几百 MB 的大事务回滚可能比执行还要慢——所以支持回滚这四个字背后是一整套庞大而精巧的存储引擎基础设施。Redis 完全没有这些包袱。它没有外键没有约束校验没有多表关联操作的就是内存里的字符串、哈希、列表、集合、有序集合。它的定位从来不是替代关系型数据库处理复杂业务事务而是一个简单高效的内存数据结构存储。设计对象不同功能取舍自然不同。2.2 Redis 的两类错误行为完全不一样前面三个 demo 展示了两个关键场景这里把差异整理成一张表错误类型触发原因示例发生阶段事务结果入队失败命令名不存在、参数个数错误MULTI 之后、EXEC 之前整个连接被标记异常EXEC 时直接 EXECABORT队列全部丢弃执行失败对字符串执行 INCR、key 类型不匹配EXEC 执行过程中出错命令返回错误其余命令照常执行已执行写入不撤销为什么会有这种差异关键在于服务器处理事务时的逻辑进入 MULTI 状态后服务器收到命令会先做命令存在性检查和参数个数检查通过了才放进事务队列。如果这两类检查没过服务器会对当前客户端连接打上一个事务已脏的标记。等 EXEC 到来服务器看到这个标记直接返回 EXECABORT清空队列整个事务宣告失败。而类型不匹配这类错误比如对字符串执行 INCR命令名和参数个数都合法所以能顺利入队。只有真正执行到那一步才发现这个 key 的内容不是整数。这时候服务器已经无法撤销前面命令的写入了只能让这条命令返回错误其他命令继续执行。这段话如果能在面试里完整讲出来基本已经超过大多数只会背结论的人。2.3 一个容易被误读的地方EXECABORT 不是回滚继续深挖一个细节。很多人看到EXECABORT Transaction discarded because of previous errors会觉得 Redis 在某种程度上也有回滚机制只是名字不一样。你要在面试里主动澄清这一点这是 Redis 对还没执行的命令做的一种保护性丢弃和回滚是两码事。回滚的前提是已经发生了修改需要把修改还原。而 EXECABORT 发生时事务队列里的命令一条都没执行数据库状态没有任何变化。可以打个比方你在超市排队结账突然发现自己忘带钱包于是直接离开队伍——这不能叫退货因为你还没付钱商品还在收银员手里。理解这个区别你就能准确定位 Redis 的能力边界它能保证一个尚未开始执行的事务不会开始执行但没有办法保证一个执行到一半的事务恢复到执行前的状态。3. 官方设计取舍为什么这个不是个深思熟虑的不需要把两类错误的逻辑理清之后真正的核心问题来了为什么 Redis 作者选择不做回滚这个问题官方文档给过明确的解释antirez 也多次在社区里阐述过自己的观点。总结下来是三层层层递进的理由。3.1 第一层命令简单错误几乎都是可预防的编程错误官方文档解释为什么 Redis 不支持回滚时给出的第一条理由很有分量Redis 命令只有在两种情况下才会失败——参数个数错误这种错误在入队阶段就会被发现或者对错误类型的 key 执行操作这种错误只能等到执行阶段才能发现。换句话说能在运行期出现的错误本质上都是可以通过简单的类型检查提前避免的它们是客户端代码里的 bug而不是数据库运行环境造成的随机故障。这个视角和关系型数据库完全不同。MySQL 里一条 UPDATE 可能因为唯一键冲突、外键约束失败、触发器抛错而中途失败这些是业务规则层面的失败不能简单定义为写代码的人笨所以数据库必须提供回滚来兜底。而 Redis 的命令都是对内存数据结构做原子操作没有外键约束没有级联更新没有复杂的业务规则校验自然也就没有非回滚不可的理由。不过话说回来编程错误也是错误线上不可能完全杜绝。所以我对官方文档这段话的理解是把能在入队阶段拦截的错误尽量拦截掉剩下的运行期错误靠客户端自己修复而不是让数据库背上回滚这个包袱。这本身就说明了 Redis 的选择——它把简单性放在第一位而不是把容错性放在第一位。3.2 第二层单线程模型下undo log 的代价尤其高Redis 是单线程执行命令的所有命令在一个线程里排队运行。很多人知道这个事实但很少把它跟回滚联系起来。实际上这两者的关系非常直接。如果 Redis 要支持回滚就必须在事务里每条写命令真正修改数据之前先把原始值保存下来。这意味着每次写操作都要多一次内存写入甚至需要某种额外的结构来组织 undo 信息。在单线程模型下这个开销会直接转化为每个事务的额外延迟而且是线性叠加的——事务里命令越多undo 信息就越重延迟就越高。更关键的是内存成本。Redis 的数据本来就是全部住在内存里的undo log 也得住在内存里。一个事务修改了 100 个 key就要额外保存 100 份修改前的数据这些内存只有在事务结束之后才能释放。对于主打低延迟、高吞吐的 Redis 来说这相当于用真金白银的内存和 CPU 去换一个使用频率极低的功能。因为真正会触发回滚的只有执行阶段那些类型错误而在作者看来这些错误属于程序员的锅。有一个细节可能很多人没意识到Redis 的命令本身执行极快事务里通常也就几十毫秒甚至几毫秒的事为了一个几乎不会触发的回滚功能拖慢每一次事务这个账怎么算都不划算。3.3 第三层作者的价值观——简单性本身就是架构的一部分Redis 作者 antirez 在很多公开讨论里表达过同一个观点Redis 的核心目标之一就是保持简单。事务不支持回滚不是还没顾得上做的暂时缺陷而是一个明确的设计决策。官方文档的那段话逻辑值得仔细品味因为 Redis 不需要回滚所以它不需要关系型数据库引擎里那套复杂的功能因此它可以更快、更简单。注意这里面的因果顺序——不是为了快所以砍掉回滚而是回滚对 Redis 这个场景没有用砍掉它让 Redis 变得更快更简单。这个因果顺序如果能在面试中讲清楚整个回答的层次立刻就不一样了。再往深处想回滚机制本身也是有风险的。传统数据库里大事务回滚可能比执行还慢回滚过程中如果宕机还需要崩溃恢复机制来保证一致性。这些复杂度如果全部引入 Redis会彻底破坏它轻量、可控、可预测的定位。Redis 应对错误的哲学是让错误尽快浮出水面用最简单明确的方式告诉客户端你这里错了而不是把所有错误都揽进一个复杂的回滚流程里慢慢处理。4. 没有回滚的 Redis业务一致性靠这三招兜底面试聊到这里如果只停留在为什么不做回滚多少有点纸上谈兵。实际开发里业务不会因为你没有回滚就放弃要求该保证的一致性还是要保证。根据我自己的项目经验有三个方案可以组合使用按优先级分别是 Lua 脚本、WATCH 乐观锁和业务补偿。4.1 WATCH 乐观锁冲突检测代替失败回滚既然不能做完再撤销那就换个思路在动手写之前先确认没人改过我要写的数据。这是 WATCH 的核心思想。典型场景是库存扣减。先用 WATCH 盯住库存 key然后读取当前库存在应用层算好扣减后的值再用 MULTI 提交写命令。如果 WATCH 之后、EXEC 之前库存 key 被其他客户端改过EXEC 会返回 nil整个事务不执行。示意如下127.0.0.1:6379 WATCH stock:12345 OK 127.0.0.1:6379 GET stock:12345 100 127.0.0.1:6379 MULTI OK 127.0.0.1:6379(TX) DECRBY stock:12345 1 QUEUED 127.0.0.1:6379(TX) EXEC (nil)返回 nil 说明别人动过库存了程序拿到 nil 之后要做的不是回滚而是重试重新 WATCH、重新 GET、重新计算、重新 EXEC。这套机制在读多写少的场景下非常好用因为整个过程没有加锁读操作永远不会被阻塞。用 WATCH 有一个实践要点重试必须限制次数。高并发场景下如果多个客户端同时抢同一个 key可能会出现大量客户端循环撞车反而把 Redis 的 CPU 打满。我一般在代码里设置 3 到 5 次重试上限超过就向上游返回操作繁忙。提示WATCH 必须在 MULTI 之前调用它在 EXEC 执行完毕或者执行 UNWATCH 之后自动失效。另外要记得EXEC 返回 nil 时需要主动处理事务未执行的分支逻辑很多线上 bug 就是忽略了这个 nil。4.2 Lua 脚本把多条命令变成一次原子执行比 WATCH 更常用、也更推荐的方式是 Lua 脚本。Redis 从 2.6 开始支持在服务端执行 Lua 脚本脚本里的所有命令会被当成一个整体原子执行执行过程中不可能插入其他客户端的命令。这比WATCH 重试更干脆不用先读、再算、再提交而是把整个判断逻辑写进脚本让服务器一次性在你眼皮底下完成。以转账为例业务要求是余额够才扣款余额不够就不动-- transfer.lua local balance tonumber(redis.call(GET, KEYS[1])) if balance nil or balance tonumber(ARGV[1]) then return -1 end redis.call(DECRBY, KEYS[1], ARGV[1]) redis.call(INCRBY, KEYS[2], ARGV[1]) return 1用 redis-cli 执行redis-cli --eval transfer.lua account:001 account:002 , 30脚本先检查余额不够直接返回 -1够才执行扣款和加款。整个过程在 Redis 内部一次性完成根本不会出现余额不足却扣款成功的中间状态自然也不需要回滚。这里有三个实战细节我必须强调。第一脚本里默认使用 redis.call它在命令出错时会立即终止整个脚本并把错误抛给调用方适合出错就必须停的逻辑如果希望某个命令出错后还能继续走后续逻辑才用 redis.pcall 自行捕获。第二很多线上事故就是因为在脚本里用了 pcall 把错误吞掉导致后续命令在错误数据上继续执行数据彻底错乱。第三尽量让脚本只包含纯函数逻辑不要在脚本里读系统时间、随机数这类不确定的值——在 Redis 7 之后脚本复制策略对纯函数性的要求比过去更严格写得不干净主从复制很容易出问题。顺带说一句现在很多 Redis 分布式锁的 SDK底层就是用 Lua 脚本保证加锁和解锁的原子性原理跟这里完全一样。理解了这个点再去看那些锁的源码会顺畅很多。4.3 业务补偿最朴素也最可靠的人工回滚WATCH 和 Lua 能覆盖 Redis 内部的原子性需求但总有一些场景是 Redis 操作本身成功了后面跟着的其他步骤失败了。这时候没有任何数据库回滚可以用只能靠业务层做补偿。最典型的案例就是先扣 Redis 库存再调下游支付服务。假设扣库存成功了但支付服务超时了你不能让 Redis 里的扣减就这么挂着必须做一笔反向操作把库存加回来。常规做法是记录操作流水把扣减前的快照和本次扣减量都存下来业务失败时执行反向增减同时给补偿操作加上幂等标记防止重复补偿。这套方案不复杂但细节特别容易踩坑。我自己在项目里吃过几次亏第一次是补偿操作忘了加幂等结果同一笔失败订单被补偿了两次第二次是补偿逻辑和正常扣减逻辑共用同一个 key结果中间有人改了库存结构补偿把别人的操作覆盖了第三次是补偿时没有打日志线上出了问题完全没法排查。做了几年 Redis 相关的开发我最大的体会是Redis 帮你保证的是单点原子跨系统的数据一致性永远要业务层自己扛这个认知越早建立越好。5. 面试现场从能背概念到能拿高分的回答框架把原理、设计和实战都捋完最后回到面试本身。这道题的回答我建议按三层来组织既不会显得在背答案又能充分展示你对 Redis 事务的真实理解。5.1 第一层先把事务的错误模型说准确面试官问出这道题首先想确认的是你有没有真正看懂 Redis 事务的执行机制。所以第一层回答不用绕弯子直接讲机制Redis 事务由 MULTI 开启命令先入队EXEC 时统一执行。错误分两类——入队阶段如果命令不存在或参数个数不对服务器会给连接打上异常标记EXEC 时直接返回 EXECABORT整个事务丢弃执行阶段如果出现类型错误比如对字符串执行 INCR出错命令返回错误其他命令照常执行Redis 不做任何撤销。到这里基础分已经拿到了。因为很多人连入队失败和执行失败是两种结果都说不清楚你能把这个差异讲明白就已经强过一大部分候选人。5.2 第二层把设计取舍讲出层次感接着展开为什么。不用一字不差地背官方文档抓住三个点就能讲出层次第一Redis 命令足够简单绝大部分错误在入队阶段就能被拦截执行阶段的类型错误本质上属于编程 bug不值得为它维护一套回滚机制第二Redis 是单线程执行模型支持回滚意味着每个事务都要额外记录 undo log这会直接变成每一次写操作的延迟和内存开销跟 Redis 的性能定位冲突第三作者把简单性当作核心设计目标回滚机制本身也有复杂性和风险砍掉它换来的简单和高效是一个明确的设计选择。如果还能补上一句这不代表 Redis 事务没有原子性——它保证的是批量命令作为一个整体执行、中间不被其他命令插入而不是保证每条命令都不出错这个层次就很完整了。5.3 第三层用实战兜底化被动为主动想再往上加分就主动把话题引向替代方案。你可以说正因为没有回滚实际项目里更常用 Lua 脚本做原子操作把判断和修改都放进脚本从源头杜绝执行到一半出错的可能并发写场景用 WATCH 乐观锁加有限次重试跨系统的场景用业务补偿。这样会给面试官留下一个明确印象你不光懂原理还真的在线上解决过问题。到了这一步这道题你已经不再是被考核而是在分享了。5.4 一个可以现场讲出来的实战片段如果面试官追问你线上真的遇到过这类问题吗我一般会提这个例子之前做一个秒杀扣减库存最初图省事用了 MULTI EXEC 配合 GET 判断结果压测时发现并发扣减经常出现读到的库存够了但 EXEC 时已经被扣完的脏读。后来把查库存、判库存、扣库存三步合并成一个 Lua 脚本压测数据立刻稳定下来。这个案例还能顺势聊出另一个经验这种高并发竞争场景下如果用 WATCH 重试重试率会非常高反而增加了无谓的客户端往返这也是我后来更倾向 Lua 的原因。最后说点个人感受。这道题我前前后后答错过两次一次在面试一次在跟同事排查线上库存对不上的问题。两次都让我意识到Redis 的不支持回滚不是它的短板而是它整个设计哲学的自然结果——它要做的是快、简单、可控的数据服务把复杂的一致性交还给业务层。如果你正在准备面试我建议放下文章之后自己打开 redis-cli 把三种事务流程各跑一遍再试着把转账场景写成 Lua 脚本执行一次。跑通的那一刻你会比看十篇文章理解得更深。

相关推荐

垃圾分类双模型协同系统:CNN+决策树分层过滤与可解释推理
垃圾分类双模型协同系统:CNN+决策树分层过滤与可解释推理

简介:本资源是一套面向高校计算机与人工智能初学者的垃圾分类系统实践项目,融合深度学习与传统机器学习方法,解决图像识别类实际工程问题。项目包含基于CNN的端到端图像分类模型与基于决策树的轻量级分类方案,兼顾精度与可解释性&… · 2026/9/24 23:18:09

TimesFM-3原生多变量时序大模型原理与工业落地
TimesFM-3原生多变量时序大模型原理与工业落地

1. 这不是又一个“刷榜”模型:TimesFM-3 的真实分量在哪? 最近朋友圈和几个技术群都在转那条消息:“谷歌第三代时序大模型来了:TimesFM-3 支持了原生多变量,三个基准双榜第一”。说实话,我看到标题第一反应… · 2026/9/24 23:18:03

VC++ COM ATL 开发 Excel 插件:从编译注册到避坑实战
VC++ COM ATL 开发 Excel 插件:从编译注册到避坑实战

简介:这份资源面向具备一定C基础、希望深入理解COM组件机制并动手扩展Excel功能的开发者,核心是用Visual C结合COM与ATL为Office Excel编写自定义插件。压缩包共23个文件,约20KB,以h头文件、c与cpp源文件为主,辅以def模… · 2026/9/24 23:18:03

MQTT协议原理与Broker服务器搭建实战:从Mosquitto到EMQX
MQTT协议原理与Broker服务器搭建实战:从Mosquitto到EMQX

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/9/25 1:00:37

创维E900V22D刷机全攻略:S905L3SB芯片兼容性解析与救砖实战
创维E900V22D刷机全攻略:S905L3SB芯片兼容性解析与救砖实战

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/9/25 1:00:31

数值优化(Numerical Optimization)学习系列-03-共轭梯度方法(Conjugate Gradient)
数值优化(Numerical Optimization)学习系列-03-共轭梯度方法(Conjugate Gradient)

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/9/25 1:00:31

深度学习新闻分类推荐系统:从TextCNN到个性化推荐
深度学习新闻分类推荐系统:从TextCNN到个性化推荐

简介:这份基于深度学习的新闻分类推荐系统Python实现源码,是专为课程设计与期末大作业准备的高分项目,下载后无需修改即可运行,适用于需要快速交付完整课题的高校学生。系统涵盖新闻数据预处理、文本分类模型训练、推荐逻辑展示等… · 2026/9/24 23:59:53

汽车电子底层软件开发:AUTOSAR与CAN总线实战解析
汽车电子底层软件开发:AUTOSAR与CAN总线实战解析

1. 这门“汽车电子底层软件开发就业课”到底在教什么?——不是写个LED闪烁就能上岗的很多人看到“汽车电子底层软件开发就业课”这个标题,第一反应是:不就是嵌入式C语言单片机CAN通信?刷几道LeetCode、调通一个STM32 CAN收发例程&… · 2026/9/24 23:59:53

Vim基础操作全攻略:保存退出、模式切换与高频命令实战
Vim基础操作全攻略:保存退出、模式切换与高频命令实战

1. 项目概述1.1 核心需求解析今天聊聊Vim。写这个题目的原因是:几乎每个后端开发者、运维人员、数据工程师某天都会遇到一个场景——深夜加班,服务器登录界面只有黑底白字,编辑器只有vi/vim,你必须在五分钟内完成一次配置修改并保… · 2026/9/24 23:59:53

数值优化(Numerical Optimization)学习系列-03-共轭梯度方法(Conjugate Gradient)
数值优化(Numerical Optimization)学习系列-03-共轭梯度方法(Conjugate Gradient)

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/9/25 1:00:31

创维E900V22D刷机全攻略:S905L3SB芯片兼容性解析与救砖实战
创维E900V22D刷机全攻略:S905L3SB芯片兼容性解析与救砖实战

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/9/25 1:00:31

MQTT协议原理与Broker服务器搭建实战:从Mosquitto到EMQX
MQTT协议原理与Broker服务器搭建实战:从Mosquitto到EMQX

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/9/25 1:00:37

了解更多?预约专属演示

我们的顾问将为您一对一讲解产品与方案

企业微信二维码