MySQL Shell实战指南:DBA的高效运维利器
做MySQL运维这些年我最常听见的一句话是“连上数据库跑个SQL”。听起来很简单可真把几套集群、几十个实例管起来以后你会发现传统的mysql命令行客户端很多时候只是“能连”离“好用”差得远。MySQL Shell 是官方提供的新一代命令行工具从管理、开发、高可用部署到数据迁移它几乎把DBA日常操作的每一个环节都重新做了一遍。这篇文章从我个人实际使用经历出发讲讲我为什么说它是MySQL DBA的最佳工具以及那些文档里写得含糊但真到生产环境才能体会到的细节。适合正在做MySQL运维、需要搭建InnoDB Cluster或者准备做版本升级的DBA参考也适合刚入行想系统接触MySQL管理工具的同学。文里提到的所有操作都是我实际用过的场景不涉及具体生产业务数据放心照做。1. 从只会敲 mysql -u root -p到主动拥抱 MySQL Shell1.1 传统客户端的三个“够用但难受”用了很多年mysql客户端它最大的优点就是“简单”一条命令进去写SQL查结果退出来。可真到了多实例、多环境、自动化要求高的场景传统客户端的问题会被放大成三个很难受的点。第一状态管理很弱。连接串、用户名、密码、端口每次都要手敲虽然可以写在 ~/.my.cnf 里但多套环境切换时非常容易混。我见过不止一个同事因为配置文件写错把测试环境的变更执行到了预发环境。第二批量操作和脚本化的能力很差。想写一个复杂的Python脚本去循环处理多个实例最终还是要调用系统命令解析文本输出。第三官方好用的工具都是独立的备份用mysqldump迁移要额外处理大批量导入搭建高可用又要手动维护一堆复制配置。这些工具割裂开来出问题的时候排查链路特别长。MySQL Shell 一开始给我的感觉是“不习惯”因为它默认不是纯SQL交互而是进入一个类似JavaScript的编程环境。但两周之后我发现自己回不去老客户端了。1.2 Shell 带来的是操作思维的转变传统客户端是“你问它答”输入SQL得到结果集。MySQL Shell 更像一个“带数据库能力的脚本环境”。你在里面写的不仅是SQL还能写变量、循环、条件判断、函数调用。比如我需要给一批实例统一做参数检查原来要写一个外部shell脚本循环执行mysql -e现在直接在Shell里连上每个实例用JavaScript或Python写逻辑全程不用离开工具。这种思维转变本质上是把“数据库操作”和“数据库管理”打通了。以前我要分三步走先连上实例查状态再退出再用别的工具去处理操作。现在所有事情都在同一个会话里完成而且结果可以存成变量、结构化成对象后面再用。对DBA来说省下来的时间只是一方面更重要的是减少了“跨工具切换”造成的上下文丢失。提示第一次打开MySQL Shell试着输入 \js 进入JavaScript模式写完几行逻辑后你会慢慢理解它为什么不是一个普通的客户端。2. 想要用好 Shell先看懂 X Protocol 和 AdminAPI2.1 X Protocol连接层重构的底层支撑很多教程一上来就让你敲代码忽略了底层协议的理解。其实MySQL Shell之所以能干这么多事核心就是它建立在 X Protocol 之上而不是传统mysql客户端用的经典协议。X Protocol 是MySQL从8.0开始支持的另一种连接协议它基于更现代的编码方式支持同步和异步消息而且可以承载结构化的文档数据模型。你可以把它理解成一条更宽的“管道”不仅能传输SQL和结果还能传输命令、文档、元数据。MySQL Shell 里的连接方式常写成 mysqlx://userhost:33060注意这个33060端口跟传统3306不一样它就是X Protocol的默认端口。理解这一点有什么实际意义当你用Shell去操作InnoDB Cluster、做Router配置、或者调用AdminAPI时很多操作需要往集群的元数据里写信息这些过程依赖X Protocol提供的能力。如果你只用传统协议连一个实例部分管理命令会提示连接方式不对这也是新手最常见的报错之一。2.2 AdminAPI用代码描述基础设施状态AdminAPI是MySQL Shell里最让我觉得值回票价的部分。在它出现之前我要手动配置主从复制改配置文件、启动复制线程、检查Position、处理延迟一整套下来至少半小时。上线之后要加一个只读节点又得走一遍类似流程。AdminAPI把这件事变成了几行代码configureInstance、createCluster、addInstance、removeInstance。它做的事情不是简单的帮你发命令而是自己管理复制用户、复制通道、状态检测、故障转移等一堆复杂的内部逻辑。我用一个生活里的类比以前配高可用像自己组装电脑每个零件都要手动匹配接口现在用AdminAPI更像买一台品牌机插上电、按开机键剩下的自检和驱动加载它帮你完成。你依然需要懂硬件的兼容性但日常操作从“折腾”变成了“配置”。2.3 JS、Python、SQL到底怎么共存MySQL Shell支持三种模式JavaScript、Python和SQL。新手常问“我应该学哪个”我的答案是取决于你要做的事。日常查数据切到SQL模式最顺手操作方式和老客户端几乎一样写一些管理脚本用JavaScript默认模式就够它官方支持最全如果你本身是Python用户用Python模式写批处理会感觉更自然。三种模式之间都可以随时用 \sql、\js、\py 切换执行结果可以跨模式使用。我自己的习惯是交互式巡检用SQL模式复杂逻辑封装成函数时写JavaScript自动化部署脚本用Python模式。要提醒的是三种模式里变量的作用域规则略有不同如果你在脚本里来回切换建议把数据通过会话变量传递避免作用域问题引发“变量找不到”的诡异报错。3. 日常运维中我用到最多的三类操作3.1 用 util 工具集处理备份与恢复如果说AdminAPI是Shell的“大脑”那 util 工具集就是Shell的“双手”。备份、恢复、导入导出过去都要靠mysqldump、mysqlimport等独立命令组合现在Shell里统一成 util.dumpInstance、util.dumpSchemas、util.loadDump 这一组函数。我最常用的是 util.dumpInstance它能把整个实例的逻辑备份加上DDL定义一起导出来。比mysqldump强的地方是它默认按表做并行分片导出的时候可以指定线程数导入时也能并行处理大表的时间会明显缩短。还有一个细节它导出的文件里包含了自定义的元数据JSON恢复的时候Shell能根据这个元数据自动处理表顺序、外键依赖等问题不需要你在外面手动排序。实际恢复的时候我们一般先在测试实例上跑一遍 util.loadDump通过 --dryRun 参数只做预检不实际导数据检查源端和目标端的差异。这个预检机制我强烈推荐它能把权限、表是否存在、字符集冲突等问题提前暴露出来而不是等你导入到一半才发现。3.2 巡检、状态查看、SQL执行的组合用法日常巡检我很少再通过“mysql客户端外部脚本”来完成。现在我常常在Shell里写一个循环遍历多个实例的连接逐个执行 SHOW STATUS、SHOW VARIABLES、查询 performance_schema 里的关键指标最后把结果汇总到本地内存变量里。举个例子要检查所有实例的复制延迟我会用JavaScript写一个 for 循环对每个实例执行 SELECT * FROM performance_schema.replication_applier_status_by_worker把返回值打印出来。整个过程在一个会话里不会有多次建立连接的浪费。另外Shell里还内置了 \watch 这类交互命令可以周期性刷新SQL结果相当于把 reload 的事也做了。我在压测的时候经常用它盯QPS和Threads_running比反复手敲SQL直观得多。注意Shell处理结果集的方式是返回JSON或表格你可以在脚本里直接访问字段。这比传统客户端的文本输出更适合做自动化判断例如 if (row.threads_running 100) 这种逻辑直接写在脚本里。3.3 升级体检checkForServerUpgrade 的细节MySQL 8.0的升级不像5.6到5.7那么简单很多老的SQL写法、字符集设置、权限模式都会成为升级后的隐患。官方提供了 util.checkForServerUpgrade 来做升级前体检这个工具是在升级前必须跑一遍的。它在检查什么简单说它扫描源实例的DDL、DML对象、系统变量配置、用户权限定义与目标版本做兼容性对比。结果会分几个级别ERROR 级别的问题会导致升级失败或数据异常WARNING 级别则建议你人工确认NOTE 级别一般是提示性的。我实际使用中遇到最多的ERROR是“使用了已废弃的GROUP BY语法”“TIMESTAMP默认值设置不合法”“旧密码插件还在使用”。这些问题在5.7时代可能一直没暴露但升级到8.0就会直接卡住。跑一次体检通常只要几十分钟却能省下后续升级窗口里数小时的排错时间。4. 从 5.7 迁移到 8.0Shell 让整个过程没有想象中痛苦4.1 迁移前的结构和兼容性检查把一套核心业务库从MySQL 5.7迁到8.0第一步不是导出数据而是做结构评估。我会先用 util.checkForServerUpgrade 跑一次源实例拿到所有不兼容项然后对每个库执行 util.dumpSchemas 里的结构导出把它导入到一个空的8.0测试实例验证DDL能否全部通过。这一步经常能发现一些隐藏雷点。比如5.7里允许把保留字当表名用8.0的某些解析器行为变了就会在导入时报语法错误。再比如utf8mb3和utf8mb4的默认差异会造成一些索引长度问题。这些如果不提前在测试实例上跑一遍DDL到了生产切换当天才暴露后果就是回退还是硬着头皮升级两头都难受。4.2 dump 和 load 的并行度设计迁移大头永远在数据导出导入。我一开始按默认参数跑 util.dumpInstance发现单表几亿行的库倒得很慢后来开始关注并行度的设置。导出端的关键参数是 threads它控制并行处理表的线程数。每个线程会负责一部分表如果是单表特别大还可以配合 bytes-per-chunk 参数把表按数据量切片。导入端的 loadDump 同样支持 threads而且默认会根据目标机的CPU核数估算并行度。我自己总结的经验是并行度不能盲目调大要结合源端和目标端的磁盘IO能力。之前在一台机械硬盘的机器上把threads调到16结果磁盘IO直接被打满整体速度反而下降。后来改成8单次导入总耗时缩短了四分之一。迁移不是越用力越好而是要让每个环节的瓶颈都处在相对均衡的状态。4.3 迁移后的验证与回退思路数据导入完成还没到庆祝的时候。我的习惯是先做三类验证数量一致性、关键业务表的行数、抽样数据对比、以及主键自增值的连续性检查。Shell里可以用 util.checkForServerUpgrade 或者自定义SQL但更常用的是写一段脚本分别统计源端和目标端每个表的行数输出差异列表。另一个重要的点是保留一份完整的备份并记录迁移开始前的binlog位点。一旦业务侧反馈数据不对可选择用Shell的增量导入或者传统复制方式补数而不是推翻重来。回退方案最好在迁移窗口前写清楚哪些操作会修改业务侧连接地址Router的流量切换如何回退这些细节一旦到了半夜两点才想很容易手忙脚乱。5. InnoDB ClusterShell 把高可用变成了“配置项”5.1 创建集群的最低要求在没有Shell以前一个高可用MySQL环境的搭建门槛是偏高的。手动做半同步复制、MMM、MHA都需要额外维护一套监控切换组件。而用Shell的AdminAPI搭建InnoDB Cluster很多步骤都被封装成了元数据操作。要求其实是硬性的至少三台实例存放数据才能保证多数派原则这也是Group Replication的基本前提。每台实例需要设置 server_id、开启 binlog、打开 GTID 模式并且确保网络端口之间互相能连通。执行 dba.checkInstanceConfiguration() 可以一次性校验这些条件是否满足省得手动逐项翻配置文件。很多新手以为Shell能自动改所有配置实际上它只是引导你改部分参数仍然需要手动设置后重启实例才能生效。我的经验是先把所有候选实例的参数准备到位再执行 createCluster这样能避免初始化到一半因为参数缺失而卡住。5.2 AdminAPI 如何管理 RouterInnoDB Cluster搭建完成后应用要连接的不是某个具体实例而是一个路由入口。MySQLRouter 就是一个轻量级的中间件它从Cluster的元数据里获取当前主节点和只读节点列表自动把读写流量分发到正确的位置。AdminAPI对这个场景的支持体现在 cluster.addRouterOption() 等命令上你可以方便地注册Router实例、查看它从集群拉取的视图。以前我们配置读写分离要在应用层维护一份节点列表节点切换后还要手动更新。现在Router会自动感知Cluster状态主节点变化后应用连接无需改动。我第一次做故障切换演练的时候有点紧张担心Router感知慢导致应用报错。实测下来状态切换时间在几秒内而且Shell里能通过 status() 查看整个集群的成员状态、延迟和角色切换过程透明可见。对DBA来说这种确定性比“脚本自动切换但不知道内部发生了什么”要舒服得多。5.3 一个节点故障时的真实处理流程在实际运维中节点故障的处理我的流程已经固定了先在Shell里执行 cluster.status()确认故障节点的状态然后调用 cluster.removeInstance() 把它从集群中移除等这台机器的服务恢复后重新执行 cluster.rejoinInstance() 或 addInstance() 加回来。有一个容易被忽略的细节removeInstance时如果故障节点完全不可达命令会提示需要加 force 参数。这说明AdminAPI设计上是带安全意识的它不会让你把一个还活着的节点莫名踢出集群而如果节点已死又允许你用强制参数继续操作。经历过一次真正的物理机宕机后我对这套流程最大的感受是可预期。每一步该做什么、屏幕上会返回什么状态都在文档里有明确描述。对于需要写故障预案的团队这比一套黑盒的第三方HA方案靠谱太多。6. 使用 Shell 一年后我最想提醒各位的几件事6.1 连接字符串和会话管理的坑MySQL Shell的连接字符串跟我们熟悉的 mysql -h -P -u -p 格式不完全一样它支持的写法更接近URI风格。新手最常踩的坑是端口号写错3306是经典SQL端口33060是X Protocol端口。如果你在Shell里用经典字符串连接却想执行AdminAPI操作很容易遇到“操作不支持”的提示。另外Shell会话默认不是持久化的每次启动都要重新连接。如果你有多个环境要连建议把连接定义写成脚本函数放到环境配置文件里。我习惯把每个环境定义成 createSession(...) 返回一个全局变量这样后面无论执行SQL还是调用AdminAPI直接引用这个变量就好。6.2 自动化脚本里的超时与输出处理把MySQL Shell写进自动化任务时最怕两种情况一是命令执行时间超过CI任务允许的超时限制二是输出内容过多撑爆日志。util.dumpInstance 这种大任务尤其需要评估时长最好通过 --threads 和分片参数控制在目标时间内完成。Shell脚本默认会把详细进度打到终端这在交互模式下没问题但丢进定时任务里就会产生大量冗余日志。建议给命令加上--quiet或调整输出级别只保留最终汇总信息。还有一点如果脚本里通过Shell执行了 SELECT 返回大量行记得用 LIMIT 或者聚合函数缩小结果集否则不仅慢还可能影响监控系统对日志的处理。6.3 安全层面密钥、权限和审计最后必须聊安全。MySQL Shell支持通过密钥文件而不是明文密码连接我强烈建议在自动化环境里用密钥方式。你可以在Shell里用\option启用连接凭据存储把密码保存在受保护的文件里脚本里只引用凭据名称。管理权限也需要单独规划。AdminAPI要求的权限比普通DBA账号更高因为它要管理复制、元数据和配置信息。切忌把root的Shell连接串写死在代码仓库里建议为每套环境单独创建专用运维账号分配最小必要权限并定期轮换密码。第七天审计日志里能看到哪些人通过Shell执行了高权限命令排查问题的时候不至于陷入“不知道谁动了集群”的尴尬。写到这里回想这一整年用MySQL Shell的经历我的实际体会是工具的强大不在于某一个功能多惊艳而在于它把DBA原本零散的“连接—查询—备份—配置—高可用”链条真正串了起来。如果你还在观望建议从备份和升级体检这两个场景切入很快就能感受到效率上的改变。最后一个私藏技巧多利用Shell的\help命令查函数签名版本升级后很多参数的默认值会变官方文档也不一定及时更新但内置帮助通常是最可靠的。

相关新闻

Code Review最佳实践:从流程设计到自动化工具与工程落地

Code Review最佳实践:从流程设计到自动化工具与工程落地

1. 为什么“开放”这件事,恰恰是Code Review的灵魂我在接手团队技术管理之后,有一件事让我特别矛盾——我从入职第一天就强调Code Review,周会也讲、考核也挂钩,但代码质量并没有明显改善。后来我把所有人提的Review意见导出来看了…

2026/10/19 5:10:12 阅读更多 →
开放式代码评审实践:从Git分支到CI质量门禁的完整工具链

开放式代码评审实践:从Git分支到CI质量门禁的完整工具链

前一阵我给团队搭了一套开放式代码评审流程,前前后后花了两三周配置,又跑了将近两个月才逐步稳定下来。今天把整套实践整理出来,名字就叫 open-code-review 吧。核心理念很简单:把代码评审从“一个人的门槛”变成“一群人的协作”…

2026/10/19 5:10:12 阅读更多 →
内核驱动开发核心要点:字符设备、设备树与中断并发管理

内核驱动开发核心要点:字符设备、设备树与中断并发管理

做Linux内核驱动开发这件事,很多从应用层转过来的开发者第一个月基本都在跟“为什么我的模块一加载就死机”较劲。说实话,内核开发和普通应用开发是完全不同的两种思维方式:应用层写崩了顶多报个段错误,在内核里写崩了直接整机宕机…

2026/10/19 5:10:12 阅读更多 →

最新新闻

STM32通过IIC驱动MPU6050六轴传感器:从时序到姿态解算实战指南

STM32通过IIC驱动MPU6050六轴传感器:从时序到姿态解算实战指南

做嵌入式这几年,被问到最多的传感器大概就是 MPU6050。这颗六轴芯片配合 STM32 的 IIC 接口,几乎是所有姿态相关项目的标准开局:两轮自平衡、云台增稳、手势遥控、跌倒检测……不管你是刚入门的新手,还是在做毕业设计的同学&#…

2026/10/19 5:55:34 阅读更多 →
Oracle数据泵单实例迁移全流程详解:从expdp到impdp

Oracle数据泵单实例迁移全流程详解:从expdp到impdp

搞Oracle数据库搬迁,绕不开的一个词就是数据泵(Data Pump)。单实例环境来回同步数据,expdp导出、impdp导入这套组合我这些年用了不下几十次,说它是最皮实的逻辑迁移方案不为过。别看这个标题“单实例环境使用数据泵&am…

2026/10/19 5:55:34 阅读更多 →
物联网设备WiFi配网实战:ESP32/ESP8266 SoftAP与SmartConfig详解

物联网设备WiFi配网实战:ESP32/ESP8266 SoftAP与SmartConfig详解

上个月帮朋友调一块 ESP32 开发板,设备本身跑得好好的,最后却卡在“怎么让设备连上他家的 WiFi”这一步。我说你直接把 SSID 和密码写在代码里不就行了?他说你自己调试当然没问题,可这个设备是要交给一个完全不会用串口、不会看代…

2026/10/19 5:55:34 阅读更多 →
artcraft:基于WebGL的轻量级创意合成工具实战

artcraft:基于WebGL的轻量级创意合成工具实战

1. 项目缘起与整体设计思路1.1 为什么会有 artcraft 这个想法做创意工具这些年,我最大的感受就是:灵感来得快,工具跟不上。脑子里冒出一个画面,想快速拼贴、调色、加纹理,结果打开专业软件要等半分钟加载,图…

2026/10/19 5:55:34 阅读更多 →
VS2017 64位下OSGQT整合实战:从编译到渲染的避坑指南

VS2017 64位下OSGQT整合实战:从编译到渲染的避坑指南

简介:这是一份面向Qt与OpenSceneGraph(OSG)三维渲染开发者的整合示例工程,基于Github上口碑较好的OSGtree项目整理而来,已在VS2017搭配64位OSG环境下完成调试,可直接运行,适合正在学习OSG与Qt混…

2026/10/19 5:55:34 阅读更多 →
CSerialPort串口类2017修正版:稳定嵌入工业控制的Win32封装

CSerialPort串口类2017修正版:稳定嵌入工业控制的Win32封装

简介:这是一份面向C开发者,特别是Windows平台串口通信初学者与中级工程师的轻量级串口类封装资源。CSerialPort类经2017年最新修正,显著降低MFC依赖性,新增_AFX宏适配MFC环境,并提供纯Win32验证程序,使非MF…

2026/10/19 5:54:34 阅读更多 →

日新闻

频率跟踪型PWM电源设计:臭氧发生器谐振点漂移与软开关实现

频率跟踪型PWM电源设计:臭氧发生器谐振点漂移与软开关实现

简介:本资源为电源技术方向的学术研究文档,聚焦介质阻挡放电型臭氧发生器电源的频率跟踪型PWM控制策略,面向电力电子、高压电源及臭氧应用领域的科研人员与工程技术人员。针对负载呈容性、等效电容随外加电压升高而增大、谐振频率随之漂移的难…

2026/10/19 0:00:47 阅读更多 →
Vibe Coding 遇上 TaoToken:把开发者思维圣殿的灵感流接入统一 Key 通道

Vibe Coding 遇上 TaoToken:把开发者思维圣殿的灵感流接入统一 Key 通道

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

2026/10/19 0:00:47 阅读更多 →
HundredCV-Chat话题建模实战教程:利用4,871个内置话题标签构建主题分析系统

HundredCV-Chat话题建模实战教程:利用4,871个内置话题标签构建主题分析系统

【免费下载链接】HundredCV-Chat 项目地址: https://ai.gitcode.com/hf_mirrors/Jax-dan/HundredCV-Chat 点击查看 免费下载 HundredCV-Chat 是一个由 100 位青年简历数据开发而来的中文多轮对话数据集,共包含 24,750 组日常闲聊对话和 4,871 个话题标签…

2026/10/19 0:00:47 阅读更多 →

周新闻

基于GMM的语音识别系统原理与MATLAB实现详解

基于GMM的语音识别系统原理与MATLAB实现详解

说到基于高斯混合模型(GMM)的语音识别系统,很多人第一反应就是一堆数学公式,觉得门槛很高。但如果你真的在MATLAB里把它落地跑通,会发现核心其实就是三件事:把声音变成特征向量,用GMM给每个类别…

2026/10/18 0:00:55 阅读更多 →
数字图像处理入门:反白、灰度化、调色板修改与导出txt实践

数字图像处理入门:反白、灰度化、调色板修改与导出txt实践

数字图像处理这四个字听起来挺唬人,但落到具体操作上,无非就是让计算机按你的想法“摆弄”像素。我在一个模拟项目X里用了一套特别经典的基础处理流程:对图像做反白、改调色板、彩色转灰度,最后把像素数据导出成txt文件。单看每一…

2026/10/18 0:00:55 阅读更多 →
机器人大脑技术盘点:具身智能的感知、决策与数据闭环

机器人大脑技术盘点:具身智能的感知、决策与数据闭环

如果你的信息流最近也天天刷到“机器人大脑”这个词,你会发现一个很有意思的现象:每个人说的“大脑”根本不是同一个东西。有人指的是大语言模型,有人指的是运动控制系统,还有人指的是能理解物理世界的端到端模型。在2026年这个时…

2026/10/19 1:30:52 阅读更多 →

月新闻

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频

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

2026/10/19 2:54:50 阅读更多 →
Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证

Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证

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

2026/10/17 17:22:31 阅读更多 →
黑夜航拍船只数据集训练YOLOV5模型全流程解析

黑夜航拍船只数据集训练YOLOV5模型全流程解析

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

2026/10/18 12:16:16 阅读更多 →