mysql不支持原生表级跨业务系统隔离,需通过数据库名分离+权限控制+应用层约束实现:优先独占数据库(如db_order),次选表前缀+视图+角色权限,应用层必须校验表名与库名,禁用动态sql和高危ddl。

MySQL本身不提供原生的“表级别跨业务系统隔离”机制——它没有类似PostgreSQL的schema-level权限隔离粒度,也没有内置多租户表自动路由能力。你要实现业务系统间表级隔离,得靠组合策略,核心是:**用数据库名/前缀 + 权限控制 + 应用层约束**,而不是依赖单个SQL语句或配置开关。
用数据库名区分业务系统,而非混用同一库下的表
这是最稳妥、最易审计的方式。每个业务系统独占一个数据库(db_order、db_user、db_payment),而不是把所有表都堆在myapp库里。
- 避免表名冲突(比如两个系统都有
user表) - 权限可精确到库:
GRANT SELECT,INSERT ON db_order.* TO 'order_app'@'%',天然隔离 - 备份、迁移、监控都能按业务边界切分,出问题不扩散
- 注意:MySQL 8.0+ 支持
CREATE DATABASE ... DEFAULT ENCRYPTION = 'Y',敏感业务可启用库级加密
若必须共库,用表名前缀 + 视图 + 权限限制
共库场景常见于遗留系统或SaaS轻量部署,但风险高,需严格补位:
- 强制约定前缀:
order_user、user_profile、payment_log,禁止无前缀建表 - 为每个业务应用创建专用账号,并只授其前缀表的权限:
GRANT ALL ON `myapp`.`order_%` TO 'order_app'@'%' - 对跨业务高频查询场景,可用视图封装并加
WHERE过滤(如CREATE VIEW v_user_public AS SELECT id,name FROM user_profile WHERE tenant_id = 'order'),但视图不阻止SELECT * FROM user_profile直查 - MySQL 8.0 的角色(
ROLE)可简化权限批量管理,但不能替代前缀约束
应用层必须做校验,不能只靠DB权限
权限是兜底手段,不是第一道防线。DBA无法拦住应用自己拼错表名或越权JOIN。
- 所有SQL应通过ORM或DAO层统一注入库/前缀变量,禁止硬编码表名(如
"SELECT * FROM user") - 连接池初始化时校验当前用户只能访问预期库/前缀,失败立即报错退出
- 关键操作(如DDL)应走审批流程,线上禁用
DROP TABLE、TRUNCATE等高危语句 - 审计日志要记录
USER()和DATABASE(),便于追溯越权行为
别踩这些坑
很多人试图用MySQL的DEFINER函数、触发器或存储过程“自动路由”,结果反而引入隐蔽耦合和调试黑洞:
-
information_schema.TABLES查询不可靠——权限不足时返回空,且无法区分逻辑归属 - 动态SQL(
CONCAT('SELECT * FROM ', @table_name))绕过权限检查,等于废掉前面所有努力 - 共享
innodb_buffer_pool和tmp_table_size参数,一个业务慢SQL可能拖垮全库,这不是隔离,是共难 -
mysqldump默认不带
--databases,误操作可能一次导出全部业务数据
真正的隔离不在SQL里,在架构决策点上:库拆分是成本最低的长期方案;前缀+权限是过渡期的折中;而指望MySQL自动识别“这是订单系统的表”——它不会,也不该会。











