触发器与函数实战:MySQL高效编程秘诀

前面我们学习了存储过程、if/case/while/repeat/loop 等流程控制语句,本节继续学习触发器、自定义存储函数,这两块是 MySQL 编程里非常常用的内容,常用于数据同步、数据校验、封装计算逻辑。

1.1 触发器(Trigger)

1.1.1 触发器简介

触发器是一种特殊的存储过程。存储过程需要我们手动使用 call 调用执行;而触发器是由表事件自动触发执行 ,当对绑定的表执行 insert、delete、update 操作时,触发器自动激活运行。

触发器常用来实现:数据完整性校验、跨表数据同步、日志记录、业务规则强制约束。

举个典型场景:学生表新增一条学生记录时,自动更新统计表里的学生总人数,保证统计数据和真实记录一致。

核心特点:触发器一定依附于某一张数据表,监控这张表的增删改事件。

1.1.2 创建触发器语法

1.只有一条执行语句的触发器

复制代码
create trigger 触发器名 before|after 触发事件
on 表名 for each row
执行语句;

2.多条执行语句的触发器(需要 begin ... end,配合修改语句结束符 delimiter)

复制代码
create trigger 触发器名 before|after 触发事件
on 表名 for each row
begin
    执行语句列表;
end;

参数说明:

  • before / after:触发时机。before 在增 / 改 / 删之前 执行;after 在操作之后执行
  • insert / update / delete:触发事件,也就是监控什么 SQL 动作
  • on 表名:触发器绑定的数据表
  • for each row:行级触发器,每修改一行数据,触发器就执行一次(MySQL 只有行级触发器)
  • 程序体:可以写普通 SQL,也可以搭配 if、循环等流程控制

1.1.3 实操示例:学生人数统计触发器

1.建库建表,初始化数据

复制代码
create database mydb16_trigger;
use mydb16_trigger;

-- 学生表
create table student1(
    id int unsigned auto_increment primary key not null,
    name varchar(50)
);
insert into student1(name) values('jack');

-- 学生总数统计表
create table student_total(total int);
insert into student_total values(1);

2.创建触发器:新增学生后,总数 + 1

复制代码
create trigger student_insert_trigger 
after insert on student1 
for each row 
update student_total set total=total+1;

3.测试触发器

复制代码
insert into student1(name) values('jenny');
select * from student_total;

结果:total 自动变为 2。

4.查看触发器

复制代码
-- 方式1
show triggers\G

-- 方式2,查询系统库information_schema
use information_schema;
select * from triggers\G
select * from triggers where trigger_name='student_insert_trigger'\G

5.删除触发器

复制代码
drop trigger if exists student_insert_trigger;

1.1.4 NEW 和 OLD 关键字

在触发器内部,通过 NEW、OLD 获取本次被操作行的数据:

触发器类型 可用关键字 含义
INSERT NEW 即将 / 已经插入的新行数据
UPDATE OLD、NEW OLD:修改前旧数据;NEW:修改后新数据
DELETE OLD 即将 / 已经被删除的旧行数据

使用格式:NEW.列名、OLD.列名

案例:一张表增删改,自动同步到另一张表
复制代码
use mydb16_trigger;
-- 主表
create table tab1(
    id int primary key auto_increment,
    name varchar(50),
    sex enum('m','f'),
    age int
);
-- 同步表
create table tab2(
    id int primary key auto_increment,
    name varchar(50),
    salary double(10,2)
);

-- 新增同步触发器
create trigger tab1_after_insert_trigger 
after insert on tab1 for each row 
insert into tab2 values(NEW.id, NEW.name, 5000);

-- 修改同步触发器
create trigger tab1_after_update_trigger 
after update on tab1 for each row 
update tab2 set name=new.name where name=old.name;

-- 删除同步触发器
create trigger tab1_after_delete_trigger 
after delete on tab1 for each row 
delete from tab2 where name=old.name;

测试命令:

复制代码
insert into tab1 values(1,"张三",'m',22);
select * from tab1;
select * from tab2;

update tab1 set name='李四' where name='张三';
select * from tab1;
select * from tab2;

delete from tab1 where name='李四';
select * from tab1;
select * from tab2;

1.1.5 触发器重要注意事项

  1. 触发器内部不能对本表执行 insert /update/delete,容易出现递归循环触发,造成死循环报错。
  2. 触发器是行级触发,批量 DML 操作(一次插入上千条)会循环触发多次,非常消耗性能。
  3. 高并发、频繁增删改的业务表,尽量少用触发器;触发器逻辑隐蔽,排错困难,业务逻辑优先写在应用层。

2.1 存储函数(自定义函数 function)

2.1.1 概念

存储函数,也叫自定义函数,用于封装一段计算逻辑,必须有且仅有一个返回值 ,可以像 MySQL 内置函数(max()、count())一样,直接写在 select 语句中使用。

存储函数 VS 存储过程对比 | 对比项 | 存储函数 function | 存储过程 procedure | | ---- | ---- | ---- | | 返回值 | 有且只有 1 个返回值 | 可以多个 / 无返回值(in/out/inout) | | 参数 | 仅支持入参,不需要写 in | in /out/inout 三种参数 | | 内部限制 | 限制多,一般不允许 DML(insert/update/delete) | 几乎无限制,可以写复杂业务、DML 语句 | | 调用方式 | select 函数名 (); | call 存储过程名 (); | | 用途 | 计算、查询,返回单个结果 | 复杂业务流程、批量操作 |

补充:存储过程可以调用函数;函数不能调用存储过程。

2.1.2 创建、调用、查看存储函数

创建语法:

复制代码
create function 函数名([参数名 类型,...])
returns 返回值类型
[函数特性]
begin
    函数体;
end;
  • returns:必填,指定返回的数据类型
  • 函数体中必须有 return 返回数据

提示:MySQL 开启 binlog 时,创建函数会报错,先执行一次:

复制代码
set global log_bin_trust_function_creators=TRUE;
示例 1:无参存储函数,统计表 emp_new 总人数
复制代码
delimiter $$
create function myfunc1_emp()
returns int
begin
    declare cnt int default 0;
    select count(*) into cnt from emp_new;
    return cnt;
end $$
delimiter ;

-- 调用
select myfunc1_emp();
示例 2:带参数存储函数,根据 sid 查询员工姓名
复制代码
delimiter $$
create function myfunc2_emp(in_sid int)
returns varchar(50)
begin
    declare out_name varchar(50);
    select name into out_name from emp_new where sid = in_sid;
    return out_name;
end $$
delimiter ;

-- 调用
select myfunc2_emp(1776);
查看存储函数
复制代码
-- 查看函数状态
show function status like 'myfunc%';

-- 查看函数创建源码
show create function myfunc2_emp;

-- 系统表查询
select * from information_schema.ROUTINES 
where ROUTINE_NAME='myfunc2_emp' AND ROUTINE_TYPE='FUNCTION'\G

2.1.3 删除存储函数

复制代码
drop function if exists myfunc1_emp;
drop function if exists myfunc2_emp;

小结

  1. 触发器是事件驱动,绑定在表上,行级触发,适合轻量数据同步,慎用在高写入场景;核心就是 NEW 和 OLD 获取变更前后的数据。
  2. 存储函数侧重计算,有返回值,可以嵌入 select;存储过程适合复杂业务逻辑,用 call 调用。
  3. MySQL 编程三件套:存储过程(流程)、触发器(自动事件)、自定义函数(计算封装),生产环境不要滥用,优先业务层实现逻辑,方便维护和排查性能问题。
相关推荐
qetfw1 小时前
UOS MariaDB 数据库:安装、最小权限与备份验证
linux·数据库·mariadb·uos
前端精髓1 小时前
调用大模型API
运维·服务器·microsoft
跨境小彭2 小时前
Temu 全托管模式下,SKU 利润核算的实践复盘
大数据·运维·人工智能·自动化·temu
李纲明2 小时前
WordPress 定时发布不跑、备份邮件延误:先核 WP-Cron 触发与回环,再改系统 Cron
运维·wordpress·定时任务·devdiy·wp-cron
数智园区合作社2 小时前
问数平台怎么把同一个指标锁成一个数
大数据·数据库·人工智能·ai
lbb 小魔仙3 小时前
Windows搭建PaddleOCR+飞书Webhook自动打卡通知机器人:识别、推送与远程触发完整教程
数据库·人工智能·prometheus·时序数据库
chushiyunen3 小时前
autoHotKey、windows自动化快捷键工具
运维·windows·自动化
逆风的蚂蚁3 小时前
linux服务器性能调整怎么落地?我把 CPU 调度、I/O 优先级和内核参数这几个旋钮都拧了一遍
linux·运维·服务器
mennekes3 小时前
临时用电线路标识:插头颜色、钟面标识配套规范
运维·网络·科技·安全·制造