编程 MySQL 9.7.4 版本号变四段,运维脚本里那条三段正则会静默截断

2026-10-21 21:02:17

MySQL 9.7.4 版本号变四段,运维脚本里那条三段正则会静默截断

MySQL 9.7.4(2026-10-20)把版本标识从 MAJOR.MINOR.PATCH 扩成 MAJOR.MINOR.PATCH.UPDATE,空的 update 段用 0 表示。数据库本身的行为没变,变的是“版本号长什么样”,以及一批靠字符串匹配取版本号的脚本。

四段号从哪几个入口拿

四个入口都能取到完整版本:VERSION_WITH_UPDATE() 函数、只读全局变量 version_with_update、命令行 mysqld --version-with-update,以及新的客户端库 API。

SELECT VERSION_WITH_UPDATE();
SELECT @@version_with_update;
mysqld --version-with-update

既有接口仍然是三段

这是 9.7.4 的 Important Change:VERSION()、version 变量、经典握手包、数字版本 ID、既有 C API 全部保持三段式兼容语义。mysql_upgrade_history 记录精确的 update 变迁,但不参与升级兼容性判断。

也就是说升级兼容的语义没动,动的是解析层。下面这些调用拿到的还是三段,patch 之后的 update 号看不到:

SELECT VERSION();
SELECT @@version;

对运维的含义很直接:监控、备份、合规巡检脚本如果只读 VERSION(),两个 update 号不同的实例会被判成同一个版本。

那条会被截断的正则

最常见的是从 mysql --version 输出里取第三列:

mysql --version | awk '{print $3}'

mysqld --version 与 mysqld --version-with-update 的输出格式不同,后者多一段。用 awk/cut 按固定列号或固定分隔符取值,一旦切到四段输出,取到的字段会错位——不是报错,是拿到一个看起来合理、实际错位的字符串。

更隐蔽的是正则。很多脚本里写着:

grep -oE '([0-9]+\.[0-9]+\.[0-9]+)'

或者等价的三段匹配。四段号 9.7.4.1 进来,这条正则只匹配到 9.7.4,截断发生在匹配成功的那一刻,脚本不会收到任何错误信号。后果是“版本相同”的误判:该升级的被跳过,或者本来合规的实例被误报。

修正写法要把第四段做成可选组,并且 anchor 住,避免只匹配前缀:

grep -oE '^[0-9]+\.[0-9]+\.[0-9]+(\.[0-9]+)?$'

如果要同时接受“从一段文本里抽取版本”的场景,去掉首尾 anchor,但保留可选段,并优先取最长匹配:

grep -oE '[0-9]+\.[0-9]+\.[0-9]+(\.[0-9]+)?' | sort -V | tail -n 1

SQL 侧同理。不要用三段正则去筛 VERSION(),直接用四段入口,或者用 SUBSTRING_INDEX 补齐:

SELECT SUBSTRING_INDEX(VERSION_WITH_UPDATE(), '.', 4) AS full_version;
SELECT @@version_with_update;

比较版本时也别比字符串——9.7.4.10 和 9.7.4.9 的字典序是反的。按段拆成数字再比较:

SELECT
  CAST(SUBSTRING_INDEX(SUBSTRING_INDEX(v, '.', 1), '.', -1) AS UNSIGNED) AS major,
  CAST(SUBSTRING_INDEX(SUBSTRING_INDEX(v, '.', 2), '.', -1) AS UNSIGNED) AS minor,
  CAST(SUBSTRING_INDEX(SUBSTRING_INDEX(v, '.', 3), '.', -1) AS UNSIGNED) AS patch,
  CAST(SUBSTRING_INDEX(v, '.', -1) AS UNSIGNED) AS update_no
FROM (SELECT @@version_with_update AS v) t;

如果脚本上游还在用三段接口,至少要把第四段补成 0 再参与比较,别让“缺失”和“零”在逻辑里分成两条路。

同一版本里另外两处校验变化

9.7.4 还回退了此前收紧的建表校验:由 InnoDB 行大小估算导致的 CREATE TABLE / ALTER TABLE 被拒,这次回退,但 ALGORITHM=INSTANT 场景下的严格估算保留。

另一处是 ALTER TABLE ... EXCHANGE PARTITION,现在双向校验 CHECK 约束与生成列表达式,WITHOUT VALIDATION 也不跳过 CHECK,违例报 ERROR 3819。如果有运维流程依赖 WITHOUT VALIDATION 绕过检查来换分区,这条路径在 9.7.4 上会直接失败,需要在执行前把约束和生成列对齐。

改脚本的优先级

先改“读版本”这一步:凡是 awk '{print $3}'、三段正则、字符串比较的地方,全部换成四段入口或可选第四段的正则。再改“版本判断”这一步:把三段语义下的相等判断,改成按段数字比较的元组比较,并把 update 号纳入判断。最后才去看升级路径本身——兼容语义没变,错的是解析层。

复制全文 生成海报 MySQL 运维脚本 版本管理 正则

推荐文章

程序员茄子在线接单