SQL详解之DCL - 数据控制语言完整指南

引言

在开发或运维数据库时,你有没有想过:「要是随便一个应用账号能删表、查密码表,那得多危险?」这时候DCL(数据控制语言)就派上用场了——它专门管「谁能碰什么、碰多少」,是SQL三大核心模块(DDL/DML/DCL)里的「安全守门员」。

本文会先讲DCL的基础概念,再对比MySQL和PostgreSQL的用户/角色、授权/撤销操作,最后给你一套开箱即用的安全最佳实践,全程无公式、代码直接复制可用。


1. DCL基础扫盲

1.1 DCL是什么?

简单说,DCL就是数据库的「门禁+房卡系统」:

  • GRANT:给人发房卡(授予对象权限)
  • REVOKE:收房卡(撤销已给的权限)
  • DENY:把人拉黑(部分数据库支持,覆盖所有授权)

1.2 常用权限表

不管MySQL还是PostgreSQL,核心权限都差不多:

权限类型适用对象通俗说明
SELECT表/视图/列看数据的权限
INSERT表/列加新数据的权限
UPDATE表/列改现有数据的权限
DELETE删现有数据的权限
CREATE库/表/视图/模式建东西的权限
DROP库/表/视图/模式删东西的权限
ALL PRIVILEGES所有对象拿到所有房卡(慎用!)

2. 先建好「人」:用户/角色管理

2.1 MySQL用户管理(5.7+通用,8.0+补特性)

MySQL里「用户」和「角色」在8.0前是分开的,8.0后才统一得像PostgreSQL。

核心操作

-- 1. 创建用户(Host很重要!防远程瞎连)
CREATE USER 'webapp'@'localhost' IDENTIFIED BY 'P@ssw0rd!202x'; -- 只能本地连
CREATE USER 'analyst'@'192.168.1.%' IDENTIFIED BY 'S3cur3Rep0rt'; -- 仅指定IP段

-- 2. 查看现有用户
SELECT User, Host FROM mysql.user;

-- 3. 改密码(8.0推荐用ALTER,兼容旧版本)
ALTER USER 'webapp'@'localhost' IDENTIFIED BY 'N3wP@ss!202x';

-- 4. 删用户
DROP USER 'analyst'@'192.168.1.%';

2.2 PostgreSQL用户/角色管理(原生统一!)

PostgreSQL里没有单独的「用户」命令,所有账号都是带不同属性的「角色」:

  • 能登录的叫LOGIN角色(就是通常说的用户)
  • 不能登录的叫NOLOGIN角色(就是组)

核心操作

-- 1. 创建能登录的用户
CREATE ROLE webapp LOGIN PASSWORD 'P@ssw0rd!202x';
-- 或者等价的简化版(psql支持CREATE USER)
CREATE USER analyst PASSWORD 'S3cur3Rep0rt';

-- 2. 创建不能登录的组(用于批量授权)
CREATE ROLE app_developer NOLOGIN;
CREATE ROLE report_reader NOLOGIN;

-- 3. 查看现有角色(psql快捷命令\du,通用SQL也行)
\du
SELECT rolname, rolsuper, rolcreatedb FROM pg_roles;

-- 4. 删角色(必须先删依赖的权限)
DROP ROLE report_reader;

3. 再管好「权限」:GRANT/REVOKE

3.1 MySQL权限授予(Host别漏了!)

MySQL的权限是绑定User@Host的,少写Host等于白授权。

常用场景

-- 1. 给Web应用表级权限(最常用!别给库级ALL)
GRANT SELECT, INSERT, UPDATE ON company_db.employees TO 'webapp'@'localhost';
GRANT SELECT ON company_db.departments TO 'webapp'@'localhost';

-- 2. 给管理员临时库级权限
GRANT ALL PRIVILEGES ON company_db.* TO 'dba_temp'@'localhost';

-- 3. 刷新权限(ALTER/GRANT后通常自动刷新,CREATE/DROP可能需要)
FLUSH PRIVILEGES;

-- 4. 查看权限
SHOW GRANTS FOR 'webapp'@'localhost';

3.2 MySQL权限撤销

-- 1. 收单个权限
REVOKE UPDATE ON company_db.employees FROM 'webapp'@'localhost';

-- 2. 收所有权限
REVOKE ALL PRIVILEGES ON company_db.* FROM 'dba_temp'@'localhost';

-- 3. 必须刷新!
FLUSH PRIVILEGES;

3.3 PostgreSQL权限授予(别忘先给模式USAGE!)

PostgreSQL有个容易踩的坑:要先给模式的USAGE权限,不然就算给了表权限,连表都看不到。

常用场景

-- 0. 必做!先给public模式的使用权限
GRANT USAGE ON SCHEMA public TO webapp;

-- 1. 给Web应用表级权限
GRANT SELECT, INSERT, UPDATE ON TABLE employees TO webapp;
GRANT SELECT ON TABLE departments TO webapp;

-- 2. 批量授权现有表(避免一个个写)
GRANT SELECT ON ALL TABLES IN SCHEMA public TO report_reader;

-- 3. 批量授权未来的表(这功能MySQL 8.0才有基础版!)
ALTER DEFAULT PRIVILEGES IN SCHEMA public 
GRANT SELECT, INSERT ON TABLES TO webapp;

-- 4. 查看权限(psql快捷命令\dp,通用SQL也行)
\dp employees

3.4 PostgreSQL权限撤销

-- 1. 收单个表权限
REVOKE UPDATE ON TABLE employees FROM webapp;

-- 2. 收未来的表权限
ALTER DEFAULT PRIVILEGES IN SCHEMA public 
REVOKE SELECT, INSERT ON TABLES FROM webapp;

4. 安全最佳实践(必看!别踩坑)

4.1 永远遵循「最小权限原则」

别给应用账号库级ALL!别给应用账号SUPERUSER!

MySQL示例:标准Web应用账号

CREATE USER 'ecommerce'@'localhost' IDENTIFIED BY 'Ec0mm3rc3!202x';
GRANT SELECT, INSERT, UPDATE ON ecommerce_db.orders TO 'ecommerce'@'localhost';
GRANT SELECT, INSERT ON ecommerce_db.order_items TO 'ecommerce'@'localhost';
GRANT SELECT ON ecommerce_db.products TO 'ecommerce'@'localhost';
FLUSH PRIVILEGES;

4.2 用「角色(组)」批量授权

不要一个个给员工授权!先建组(NOLOGIN角色),把权限给组,再把人加到组里。

PostgreSQL示例:标准公司权限体系

-- 1. 建组
CREATE ROLE app_developer NOLOGIN;
CREATE ROLE sales_reader NOLOGIN;
CREATE ROLE finance_writer NOLOGIN;

-- 2. 给组批量授权
GRANT USAGE ON SCHEMA public TO app_developer, sales_reader, finance_writer;
GRANT ALL PRIVILEGES ON ALL TABLES IN SCHEMA public TO app_developer;
GRANT SELECT ON ALL TABLES IN SCHEMA public TO sales_reader;
GRANT SELECT, UPDATE ON finance_salaries TO finance_writer;

-- 3. 给未来的表授权(自动继承到组)
ALTER DEFAULT PRIVILEGES IN SCHEMA public 
GRANT ALL PRIVILEGES ON TABLES TO app_developer;

-- 4. 加人到组
CREATE USER lily LOGIN IN ROLE app_developer PASSWORD 'L1lyDev!202x';
CREATE USER tom LOGIN IN ROLE sales_reader PASSWORD 'T0mS3ll!202x';

4.3 限制登录来源(MySQL的Host、PostgreSQL的pg_hba.conf)

别随便用@%(允许所有IP)! 尤其是内网和生产环境的账号。


5. MySQL vs PostgreSQL DCL核心差异(1分钟速查)

特性MySQLPostgreSQL
用户/角色关系8.0后统一,之前分开原生统一(所有都是角色)
必给的基础权限无特殊要求必须先给模式USAGE
批量授权未来对象8.0+有限支持ALTER DEFAULT PRIVILEGES完善
权限绑定对象绑定User@Host绑定角色

相关教程

最后再啰嗦一句:定期(比如每月)用`SHOW GRANTS`(MySQL)或`\du`+`\dp`(PostgreSQL)审查一次用户权限,及时收走离职/闲置账号的权限!

总结

DCL就是数据库的「安全盾牌」,记住三个核心点:

  1. 先建角色(组),批量授权
  2. 永远遵循最小权限原则
  3. 限制登录来源,定期审查权限

MySQL的DCL简单易上手,适合快速部署;PostgreSQL的DCL更精细,适合高安全要求的场景。