From 3625e8b3d88a4f9f7a9e79fd12b42dd17aed5dd3 Mon Sep 17 00:00:00 2001 From: xuans Date: Sun, 27 Sep 2026 23:16:08 +0800 Subject: [PATCH] =?UTF-8?q?=E4=BF=AE=E5=A4=8DMySQL=E4=BA=8B=E4=BB=B6?= =?UTF-8?q?=E5=9B=9E=E5=BD=92=E6=B5=8B=E8=AF=95=E5=89=8D=E7=BD=AE=E6=9D=A1?= =?UTF-8?q?=E4=BB=B6=E5=B9=B6=E8=A1=A5=E5=85=85=E6=81=A2=E5=A4=8D=E8=BF=90?= =?UTF-8?q?=E7=BB=B4=E8=A6=81=E6=B1=82?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 补齐触发器测试精确库授权中的事件权限,等待多语句事件完整执行及线程退出。补充事件备份、恢复维护权限、调度与官方客户端边界。 验证:MySQL 5.7/8.0 隔离实库专项全部通过;后端无缓存全量测试、go vet、依赖校验通过。本次不代表生产部署验收。 --- .../cli/mysql_programs_integration_test.go | 14 +++++++++++--- .../cli/mysql_triggers_integration_test.go | 2 +- doc/生产部署与运维说明.md | 10 ++++++++-- 3 files changed, 20 insertions(+), 6 deletions(-) diff --git a/backend/internal/cli/mysql_programs_integration_test.go b/backend/internal/cli/mysql_programs_integration_test.go index e5bf8de..4f11201 100644 --- a/backend/internal/cli/mysql_programs_integration_test.go +++ b/backend/internal/cli/mysql_programs_integration_test.go @@ -103,16 +103,24 @@ func TestMySQLRealOfficialStoredPrograms(t *testing.T) { t.Fatal(err) } deadline := time.Now().Add(10 * time.Second) - var value int + var completed bool + var workers int for time.Now().Before(deadline) { - if err := verify.DB.QueryRowContext(t.Context(), "SELECT value FROM interop WHERE id = 1").Scan(&value); err != nil { + if err := verify.DB.QueryRowContext(t.Context(), "SELECT value = 115 AND label = '事件;执行' FROM interop WHERE id = 1").Scan(&completed); err != nil { t.Fatal(err) } - if value == 115 { + // 多语句事件逐条提交,必须等待完整结果及工作线程退出,避免读取中间状态或影响下一用例。 + if err := server.Admin().QueryRowContext(t.Context(), "SELECT COUNT(*) FROM information_schema.PROCESSLIST WHERE COMMAND = 'Connect'").Scan(&workers); err != nil { + t.Fatal(err) + } + if completed && workers == 0 { break } time.Sleep(25 * time.Millisecond) } + if !completed || workers != 0 { + t.Fatal("事件未在预期时间完成全部更新并退出工作线程") + } checkMySQLInteropValue(t, target, "SELECT CONCAT(value, '|', label) FROM interop WHERE id = 1", "115|事件;执行") checkMySQLInteropValue(t, source, "SELECT CONCAT(value, '|', label) FROM interop WHERE id = 1", "10|原始值") }) diff --git a/backend/internal/cli/mysql_triggers_integration_test.go b/backend/internal/cli/mysql_triggers_integration_test.go index 81a0233..742fde6 100644 --- a/backend/internal/cli/mysql_triggers_integration_test.go +++ b/backend/internal/cli/mysql_triggers_integration_test.go @@ -153,7 +153,7 @@ func TestMySQLRealTriggerPrivileges(t *testing.T) { statements = append(statements, "GRANT TRIGGER ON "+schema+".* TO "+account) case "escaped_schema": escaped := strings.ReplaceAll(parsed.DBName, "_", string(rune(92))+"_") - statements = append(statements, "GRANT SELECT, TRIGGER ON "+quoteMySQLIdentifier(escaped)+".* TO "+account) + statements = append(statements, "GRANT SELECT, TRIGGER, EVENT ON "+quoteMySQLIdentifier(escaped)+".* TO "+account) case "shadowed_schema": statements = append(statements, "GRANT TRIGGER ON `scert%`.* TO "+account) case "shadowed_exact": diff --git a/doc/生产部署与运维说明.md b/doc/生产部署与运维说明.md index e462d54..9f1412d 100644 --- a/doc/生产部署与运维说明.md +++ b/doc/生产部署与运维说明.md @@ -275,9 +275,15 @@ MySQL 自有备份已增加触发器导出。维护账户除读取表结构/数 MySQL 自有备份同时导出存储过程和函数。5.7 维护账户需对 `mysql.proc` 具有完整 `SELECT` 权限;8.0 需具有有效 `SHOW_ROUTINE`,或没有被当前库部分撤销限制的全局 `SELECT`。仅有库级 `EXECUTE`、`CREATE ROUTINE` 或元数据中看不到例程,不能证明完整定义可见;即使源库当前没有例程,检查仍会执行。8.0 支持通过已启用角色获得权限,不会自动启用角色或扩权。请优先由管理员评估专用维护账户及最小可见权限,不给业务账户照搬测试授权。 -恢复时先写入所有表数据,再创建例程,最后创建触发器,保留原定义者、SQL 模式和创建字符集;同名例程会先删除再创建。目标账户需具备相应对象管理权限、数据库 `ALTER` 权限,并满足实际服务器对定义者和二进制日志的权限要求。不能照搬隔离测试账户的全局管理权限,也不能通过开启全局信任来绕过验证。 +恢复时先写入所有表数据,再创建例程和触发器,恢复外键检查后最后创建事件,保留原定义者、SQL 模式和创建字符集;同名例程和事件会先删除再创建。目标账户需具备相应对象管理权限、数据库 `ALTER` 权限,并满足实际服务器对定义者和二进制日志的权限要求。不能照搬隔离测试账户的全局管理权限,也不能通过开启全局信任来绕过验证。 -自有导出对事件、视图及完整表清单的支持尚未补齐;例程目前验证了 UTF-8 和 Latin-1 的指定场景,不代表任意字符集、SQL 模式或跨服务器定义者迁移通过。成功恢复后还原会话属性和源库数据库排序规则;中途失败的 DDL 原子回滚及排序规则回退仍需验证。不会清除备份之外的额外目标例程,也不恢复数据库账号授权。具体证据和未完成边界见《构建版本与数据库支持矩阵》第十一、十二节,不能据此宣布完整 MySQL 灾难恢复通过。 +MySQL 自有备份已增加事件导出,保存计划、时区、启停状态和创建会话属性。维护账户必须具有可证明的有效全局或库级 `EVENT` 权限,即使当前看不到事件也不能省略;表级授权不能证明事件完整可见。已经到期且重新创建会被自动删除或改变启用状态的事件,以及无法验证时区的事件,会被明确拒绝,不覆盖已有备份。 + +Scert 恢复需要有效全局 `PROCESS` 权限以检查事件工作线程。请在维护窗口由管理员停止事件调度,等待工作线程自然退出,并防止其他会话重新开启调度或修改对象;仅将调度器设为 `OFF` 不代表已有工作线程已经退出。产品不会自行修改全局调度器、终止线程或扩大权限。调度器为 `ON` 且目标库已有启用事件,或导入内容可能启用事件时,Scert 会在执行首条恢复语句前拒绝;全部事件禁用且没有运行线程的情况不受此项限制。工作线程识别会保守拒绝其他处于 `Connect` 状态的连接。 + +事件恢复后发现自动删除、自动禁用等影响对象完整性的警告时,Scert 会停止后续语句并报告失败,但不承诺回滚已经执行的 DDL。使用官方 MySQL 客户端导入时不会执行 Scert 的预检,管理员必须自行落实上述维护窗口、检查警告并核验对象、计划、时区及启停状态,完成核验后再恢复调度。 + +自有导出对视图及完整表清单的支持尚未补齐;例程和事件的 UTF-8、Latin-1 指定场景不代表任意字符集、SQL 模式或跨服务器定义者迁移通过。成功恢复后还原会话属性和源库数据库排序规则;中途失败的 DDL 原子回滚及排序规则回退仍需验证。不会清除备份之外的额外目标例程或事件,也不恢复数据库账号授权。例程历史证据见《构建版本与数据库支持矩阵》第十一、十二节;事件实现及正式 Go 测试已纳入代码,但不能据此宣布完整 MySQL 灾难恢复或生产部署验收通过。 ### 7.2 停服备份