查 INFORMATION_SCHEMA.ROUTINES 的 ROUTINE_DEFINITION 字段最可靠,需用大小写不敏感校对或正则匹配(如 REGEXP '(?i)[a-z0-9_]+.[a-z0-9_]+')识别跨库引用,同时结合 DEFINER 权限与触发器 ACTION_STATEMENT 综合判断。

查 INFORMATION_SCHEMA.ROUTINES 里是否含跨库表名
存储过程或函数体内若出现 db_name.table_name 这类带库名前缀的引用,就属于跨库操作。直接查 INFORMATION_SCHEMA.ROUTINES 的 ROUTINE_DEFINITION 字段最可靠:
- 必须用
COLLATE utf8mb4_general_ci或类似校对规则,避免大小写漏匹配(比如mydb.users和MYDB.USERS) - 正则匹配更稳妥:
SELECT ROUTINE_NAME, ROUTINE_TYPE FROM INFORMATION_SCHEMA.ROUTINES WHERE ROUTINE_SCHEMA = 'target_db' AND ROUTINE_DEFINITION REGEXP '(?i)[a-z0-9_]+\.[a-z0-9_]+'; - 注意排除误报:像
mysql.proc这种系统库引用通常不算业务跨库,但得结合实际权限模型判断
触发器中检查 NEW/OLD 引用是否指向其他库
触发器不能直接跨库更新,但能跨库 SELECT —— 这是常见隐患点。重点扫描 INFORMATION_SCHEMA.TRIGGERS 的 ACTION_STATEMENT:
- 执行
SELECT TRIGGER_NAME, EVENT_OBJECT_TABLE, ACTION_STATEMENT FROM INFORMATION_SCHEMA.TRIGGERS WHERE TRIGGER_SCHEMA = 'your_db'; - 人工或脚本 grep
SELECT.*[a-z0-9_]+\.[a-z0-9_]+、INSERT INTO [a-z0-9_]+\.等模式 - 特别警惕
SELECT ... FROM other_db.t1 WHERE id = NEW.id这类语句:它不报错,但会拖慢性能、破坏事务隔离性
用 SHOW CREATE PROCEDURE 检查 DEFINER 权限范围
DEFINER 用户权限决定了跨库操作能否真正执行。即使语法合法,权限不足也会在运行时报错:
- 执行
SHOW CREATE PROCEDURE proc_name,看开头是否为DEFINER=`user`@`host` - 然后查该用户是否有目标库的
SELECT/INSERT/UPDATE权限:SHOW GRANTS FOR 'user'@'host'; - 如果
DEFINER是root@localhost,而过程里访问了log_db.audit_log,但线上root被限制只读app_db,那就必然失败
导出 SQL 时注意 --routines 不含跨库权限信息
用 mysqldump --routines 导出存储过程时,DEFINER 会被原样保留,但不会附带对应用户的权限定义:
- 迁移后若目标库没创建同名用户或未授跨库权限,过程看似存在,一调就报
ERROR 1142 (42000): INSERT command denied to user - 安全做法是导出时加
--skip-definer,再手动补SQL SECURITY INVOKER,让权限按调用者身份判断 - 或者干脆在开发规范里禁止跨库引用,强制通过应用层聚合数据


















