视图、函数和过程
MySQL 中的视图、函数和过程 —— 教学式详解与最佳实践
一、视图(View)
✅ 什么是视图?
视图(View)是数据库中一种虚拟表,本质是数据库中保存的 SQL 查询结果。当你访问一个视图时,数据库实际上是在执行它背后的 SQL 查询。
✅ 本质上是“只读的查询封装”
✅ 为什么使用视图?
优势 | 场景应用示例 |
---|---|
隐藏敏感字段 | 只让普通用户访问 eno , ename , job 字段,隐藏工资信息 |
逻辑抽象、统一接口 | 多张表关联的复杂查询封装成一个视图,方便调用 |
简化权限控制 | 给用户授权访问视图而非底层表 |
保持应用与数据库结构的解耦 | 表结构变化只需修改视图,不影响应用逻辑 |
✅ 教学示例
创建视图 vw_emp_simple
,仅包含基本员工信息:
create view vw_emp_simple as
select eno, ename, job, dno from tb_emp;
使用视图查询员工列表:
select * from vw_emp_simple;
删除视图:
drop view if exists vw_emp_simple;
⚠️ 不可更新的视图(Best Practice)
以下情况不能更新视图(无法用于 insert/update/delete
):
- 使用了聚合函数:
sum()
、avg()
等 - 使用
distinct
、group by
、union
- 包含子查询
- 组合了多个视图或只读源
✅ 最佳实践:
- 把只读查询封装成视图;
- 更新操作仍应直接操作数据表;
- 不要在视图中加入业务逻辑判断(如 if/else)。
二、函数(Function)
✅ 什么是函数?
MySQL 中的自定义函数类似 Python 或 JavaScript 的函数,用来封装重复使用的逻辑,可用于查询语句中直接调用并返回值。
✅ 使用场景
场景 | 示例 |
---|---|
统一格式化处理 | 统一将超长字符串截断成指定长度 |
可读性提升 | 把复杂的判断逻辑抽象为函数,提高 SQL 的可维护性 |
用于 SELECT 中的内联处理 |
如 SELECT fn_name(col) FROM ... |
✅ 教学示例:字符串截断函数
delimiter $$
create function fn_truncate_string(
content varchar(10000),
max_length int unsigned
) returns varchar(10000) no sql
begin
declare result varchar(10000) default content;
if char_length(content) > max_length then
set result = left(content, max_length);
set result = concat(result, '……');
end if;
return result;
end $$
delimiter ;
调用函数:
select fn_truncate_string('和我在成都的街头走一走,直到所有的灯都熄灭了也不停留', 10) as short_string;
输出结果:
和我在成都的街头走一……
✅ 注意事项:
- 修改
delimiter
语句避免语句体内的;
提前终止;- 若函数中含有 SQL 查询语句,则必须加
reads sql data
;- 尽量避免函数中操作表数据 —— 会引发性能瓶颈。
三、过程(Procedure)
✅ 什么是存储过程?
过程(Procedure)是一组预定义 SQL 的组合,一次定义、多次执行,尤其适合执行一系列逻辑操作或事务处理。
✅ 区别函数:过程可以有多个输出参数、可执行事务与写操作;函数只能返回单个值。
✅ 使用场景
场景 | 示例 |
---|---|
封装复杂业务逻辑 | 如:订单入库 + 库存检查 + 生成通知 + 写日志 |
提高性能 | 减少客户端与数据库之间交互次数 |
统一操作流程 | 薪资批量调整、数据清理、批处理逻辑等 |
✅ 教学示例:薪资普调过程
delimiter $$
create procedure sp_upgrade_salary()
begin
declare flag boolean default 1;
declare continue handler for sqlexception set flag=0;
start transaction;
update tb_emp set sal = sal + 300 where dno = 10;
update tb_emp set sal = sal + 800 where dno = 20;
update tb_emp set sal = sal + 500 where dno = 30;
if flag then
commit;
else
rollback;
end if;
end $$
delimiter ;
调用过程:
call sp_upgrade_salary();
删除过程:
drop procedure if exists sp_upgrade_salary;
✅ 最佳实践:
- 尽量使用事务控制流程(
start transaction
/commit
/rollback
);- 给过程增加异常处理器提高健壮性;
- 避免在高并发系统中频繁调用过程,避免数据库成为性能瓶颈。
四、最佳实践总结
功能类型 | 建议用途 | 禁忌与限制 |
---|---|---|
视图 | 简化查询,隔离权限,封装复杂逻辑 | 不用于更新;不要包含子查询或聚合 |
函数 | 格式处理,计算逻辑封装 | 不用于数据更新;避免内部 SQL 写操作 |
过程 | 多步操作封装、事务处理、批量更新 | 控制逻辑越复杂,维护成本越高,应适度使用 |
五、教学延伸:实战建议
✅ 使用场景对比
场景 | 使用工具 |
---|---|
对外暴露敏感数据的子集 | ✅ 使用视图 |
批量处理员工奖金 | ✅ 使用过程 |
格式统一展示员工昵称 | ✅ 使用函数 |
六、进一步学习建议
- 初学者推荐阅读《MySQL必知必会》打基础;
- 对于性能优化、事务控制、索引与锁机制,推荐《高性能MySQL》;
- 熟悉事务隔离级别与并发问题:建议重点掌握 MySQL 的
REPEATABLE-READ
与READ COMMITTED
两种事务级别。
如需扩展学习「触发器(Trigger)」、「事件调度器(Event Scheduler)」、「游标(Cursor)」等内容,也可继续深入了解。
七、小结:何时用视图/函数/过程?
操作 | 适合的封装方式 |
---|---|
查询 + 隐私保护 | ✅ 视图 |
查询 + 格式化 | ✅ 函数 |
多步更新 + 事务 | ✅ 过程 |
如需可打印版学习卡片或《SQL进阶实战50例》复习文档,也可以告诉我,我可以帮你制作 ✍️