Mysql

关注公众号 jb51net

关闭
首页 > 数据库 > Mysql > MySQL DCL、函数与约束

MySQL DCL、函数与约束详解( 安全、效率、完整性的三板斧)

作者:泡泡鱼(敲代码中)

这篇文章给大家介绍MySQL学习笔记:DCL、函数与约束 —— 安全、效率、完整性的三板斧,本文结合实例代码给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友参考下吧

学完 DML 的增删改、DQL 的查询之后,昨天把 MySQL 基础篇剩下的三块硬骨头啃完了: DCL(数据控制语言)、函数、约束。这三块内容看起来零散,其实各守一条主线:

这篇笔记把三块内容串起来讲,语法 + 案例 + 我的理解,希望能帮到同样在学 MySQL 的朋友。

一、DCL:数据库的 “门禁系统”

DCL 全称 Data Control Language(数据控制语言),用来管理数据库用户、控制访问权限。这类 SQL 开发人员用得少,主要是 DBA(数据库管理员)在操作,但理解它对你理解 “数据库安全” 很有帮助。

1.1 管理用户:用户 = 用户名 @ 主机名

在 MySQL 中,一个用户不是只有 “用户名”,而是由用户名 + 主机名共同唯一标识:

-- 查询所有用户(用户信息存放在 mysql 库的 user 表)
SELECT * FROM mysql.user;
-- 创建用户:'itcast' 只能在本机(localhost)访问
CREATE USER 'itcast'@'localhost' IDENTIFIED BY '123456';
-- 创建用户:'heima' 可以在任意主机(%)访问
CREATE USER 'heima'@'%' IDENTIFIED BY '123456';
-- 修改密码(mysql_native_password 是认证插件)
ALTER USER 'heima'@'%' IDENTIFIED WITH mysql_native_password BY '1234';
-- 删除用户
DROP USER 'itcast'@'localhost';

关键点

1.2 权限控制:能干什么,细到 “库。表”

-- 查询某用户的权限
SHOW GRANTS FOR 'heima'@'%';
-- 授予权限:授予 heima 操作 itcast 库所有表的所有权限
GRANT ALL ON itcast.* TO 'heima'@'%';
-- 撤销权限
REVOKE ALL ON itcast.* FROM 'heima'@'%';

常见权限有:ALL / ALL PRIVILEGES(所有)、SELECTINSERTUPDATEDELETEALTERDROPCREATE 等。

关键点

最小权限原则是数据库安全的第一课:给用户只授 “够用” 的权限。业务账号通常只需要 SELECT/INSERT/UPDATE/DELETE,结构变更(ALTER/DROP)留给 DBA 账号。别图省事直接 GRANT ALL

Host 就是安全边界:'xxx'@'%' 等于把数据库暴露给任意 IP。生产环境如果业务账号用了 %,风险相当大 —— 最好精确到应用服务器所在的网段或具体 IP。

生产环境不要用 root 跑业务:root 权限无法精细限制,出了问题也没有追溯手段。这也是 “最小权限账号” 存在的意义。

补充两点课件没细说的:

二、函数:把计算交给数据库

函数是 MySQL 内置好的一段可调用代码,业务里直接调用即可。课件用两个场景引入:算入职天数(用 DATEDIFF)、判分数等级(用 CASE WHEN)。MySQL 函数分四类:字符串、数值、日期、流程。

2.1 字符串函数

函数功能
CONCAT(S1,S2,...)字符串拼接
LOWER(str) / UPPER(str)全部转小写 / 转大写
LPAD(str,n,pad) / RPAD(str,n,pad)左 / 右填充到 n 个字符
TRIM(str)去掉首尾空格
SUBSTRING(str,start,len)从 start 起截取 len 个字符

经典案例 —— 工号补零:业务变更要求工号统一为 5 位,不足前面补 0:

UPDATE emp SET workno = LPAD(workno, 5, '0');
-- 1号员工工号 1 → 00001

这个场景在真实业务里非常常见:订单号、学号、流水号要统一长度,LPAD/RPAD 就是干这个的。

2.2 数值函数

函数功能
CEIL(x)向上取整
FLOOR(x)向下取整
MOD(x,y)x/y 的模(余数)
RAND()返回 0~1 随机数
ROUND(x,y)四舍五入,保留 y 位小数

经典案例 ——6 位随机验证码

SELECT LPAD(ROUND(RAND() * 1000000, 0), 6, '0');

思路拆解:RAND() 得到 0~1 随机数 → 乘 1000000 放大 → ROUND(...,0) 取整去掉小数 → LPAD(...,6,'0') 不足 6 位补零。三个函数嵌套在一起,从里往外读,逻辑很清晰。

2.3 日期函数

函数功能
CURDATE() / CURTIME() / NOW()当前日期 / 当前时间 / 当前日期时间
YEAR(date) / MONTH(date) / DAY(date)提取年 / 月 / 日
DATE_ADD(date, INTERVAL expr type)日期加指定时间间隔
DATEDIFF(date1, date2)两个日期相差天数

经典案例 —— 入职天数:查询所有员工的入职天数,按入职天数倒序:

SELECT name, DATEDIFF(CURDATE(), entrydate) AS 'entrydays'
FROM emp
ORDER BY entrydays DESC;

2.4 流程函数

函数功能
IF(value, t, f)value 为真返回 t,否则返回 f
IFNULL(value1, value2)value1 非空返回它,否则返回 value2
CASE WHEN 条件 THEN 结果 ... ELSE 默认 END条件判断(可多分支)
CASE 表达式 WHEN 值 THEN 结果 ... END等值判断

经典案例 —— 工作地址分级:北京 / 上海 → 一线城市,其他 → 二线城市:

SELECT name,
       (CASE workaddress WHEN '北京' THEN '一线城市'
                         WHEN '上海' THEN '一线城市'
                         ELSE '二线城市' END) AS '工作地址'
FROM emp;

经典案例 —— 成绩分档:≥85 优秀、≥60 及格、否则不及格(注意这里用的是 CASE WHEN 条件式写法,因为要做范围判断):

SELECT id, name,
       (CASE WHEN math >= 85 THEN '优秀'
             WHEN math >= 60 THEN '及格'
             ELSE '不及格' END) AS '数学',
       (CASE WHEN english >= 85 THEN '优秀'
             WHEN english >= 60 THEN '及格'
             ELSE '不及格' END) AS '英语'
FROM score;

单行函数 vs 聚合函数:今天学的都是单行函数(对一行数据计算,返回一行结果);之前学的 COUNT/AVG/MAX聚合函数(多行压成一行)。搞清楚这个分类,读 SQL 心里更有数。

函数可以嵌套:验证码案例就是三层嵌套。嵌套函数的读法是 “从里往外”—— 最里层先算,结果作为外层参数。

几个易错点

补充常用函数(课件没列但很常用):CHAR_LENGTH(字符数)、REPLACE(替换)、DATE_FORMAT(日期格式化)、TIMESTAMPDIFF(更灵活的时间差)、LAST_DAY(当月最后一天)。

一个进阶提醒:在 WHERE 里对字段套函数(如 WHERE YEAR(entrydate) = 2020)会导致该字段的索引失效、全表扫描。函数不是随便放哪都行,“函数用在哪” 是 SQL 优化的经典考点,进阶篇会展开。

三、约束:数据完整性的守门员

概念:约束是作用于表中字段上的规则,用于限制存储的数据。目的:保证数据库中数据的正确性、有效性和完整性

3.1 六种约束总览

约束描述关键字
非空约束限制字段不能为 NULLNOT NULL
唯一约束保证字段值唯一、不重复UNIQUE
主键约束一行数据的唯一标识,非空且唯一PRIMARY KEY
默认约束未指定值时采用默认值DEFAULT
检查约束(8.0.16+)保证字段值满足某个条件CHECK
外键约束让两张表建立连接,保证一致性FOREIGN KEY

约束可以在创建表修改表时添加。

3.2 一个建表演示

CREATE TABLE tb_user(
    id int AUTO_INCREMENT PRIMARY KEY COMMENT 'ID唯一标识',
    name varchar(10) NOT NULL UNIQUE COMMENT '姓名',
    age int CHECK (age > 0 && age <= 120) COMMENT '年龄',
    status char(1) DEFAULT '1' COMMENT '状态',
    gender char(1) COMMENT '性别'
);

验证约束是否生效:

3.3 外键约束:让两张表 “拉上关系”

外键用来让两张表的数据之间建立连接,从而保证数据的一致性和完整性。典型场景:员工表 emp.dept_id 关联部门表 dept.id

课件里做了一个很好的实验:不建外键时,直接删除 dept 表 id=1 的部门会成功,但 emp 表里还有一堆员工挂着 dept_id=1—— 数据 “悬空” 了,这就是不一致。外键就是来解决这个问题的。

-- 建表时添加外键
[CONSTRAINT 外键名] FOREIGN KEY (外键字段) REFERENCES 主表(主键列);
-- 给已有表添加外键(emp.dept_id → dept.id)
ALTER TABLE emp ADD CONSTRAINT fk_emp_dept_id
FOREIGN KEY (dept_id) REFERENCES dept(id);
-- 删除外键
ALTER TABLE emp DROP FOREIGN KEY fk_emp_dept_id;

加了外键之后,再删除 dept 里被引用的记录会直接报错—— 外键生效了。

删除 / 更新行为:父表记录被删 / 改时,子表怎么办?有四种选择(配图见下):

行为效果
NO ACTION / RESTRICT子表有引用就拒绝删除 / 更新(默认,两者一致)
CASCADE子表级联删除 / 更新
SET NULL子表外键列置为 NULL(要求外键允许 NULL)
SET DEFAULT置为默认值(InnoDB 不支持
-- 级联示例:父表更新/删除时,子表跟着变
ALTER TABLE emp ADD CONSTRAINT fk_emp_dept_id
FOREIGN KEY (dept_id) REFERENCES dept(id)
ON UPDATE CASCADE ON DELETE CASCADE;

约束的本质是把规则交给数据库。没有约束时,数据质量只能靠应用代码 “自觉”;一旦换入口(DBA 直接改库、脚本批量导入),脏数据就进来了。约束是数据库层面的守门员,从源头拦截。

主键 vs 唯一约束

CHECK 约束的版本坑CHECK 语法在 MySQL 5.7 就能写,但 8.0.16 之前会被静默忽略—— 不报错、不生效。所以别以为写了 CHECK 就万事大吉,先确认版本。

外键 vs 逻辑外键(面试高频)

CASCADE 是双刃剑:级联删除确实方便,但 DELETE FROM dept WHERE id=1 可能连带删掉几百条员工记录,删错不可逆。生产环境对级联要非常谨慎。课件也提醒:业务系统中一般不会修改主键值

四、写在最后

至此,MySQL 基础篇的 SQL 五类语言(DDL、DML、DQL、DCL、TCL)已经学完四类,下一站是多表查询和事务。

练习建议:把 tb_user 建出来亲手试一遍约束;用 emp 表分别实现 “工号补零”" 入职天数 "“工作地址分级” 三个案例;再试试给两张表加外键,观察 CASCADESET NULL 的区别 —— 动手跑一遍,比看十遍笔记记得牢。

到此这篇关于MySQL DCL、函数与约束详解( 安全、效率、完整性的三板斧)的文章就介绍到这了,更多相关MySQL DCL、函数与约束内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

您可能感兴趣的文章:
阅读全文