MySQL数据库精研之旅第二十期:存储过程,数据处理的全能工具箱(三)

专栏:MySQL数据库成长记

个人主页:手握风云

目录

一、存储函数

[1.1. 语法](#1.1. 语法)

[1.2. 示例](#1.2. 示例)

二、触发器

[2.1. 触发器是什么](#2.1. 触发器是什么)

[2.2. 语法](#2.2. 语法)

[2.3. 示例](#2.3. 示例)


一、存储函数

1.1. 语法

MySQL 存储函数是有返回值的存储过程,参数只能是 IN 类型(无需显式声明 IN,默认即为输入参数,不支持 OUT 和 INPUT 类型),类似于内置函数。存储函数与存储过程的主要区别在于存储函数必须包含 RETURN 语句,且返回值类型需与 CREATE FUNCTION 中 RETURNS 指定的类型一致,而存储过程则不⼀定。

sql 复制代码
-- 存储函数创建语法
CREATE FUNCTION 存储函数名称 ([参数列表])
RETURNS type [characteristic ...]
BEGIN
    -- SQL语句
    RETURN ...;
END;


-- characteristic(特性)选项说明
[NOT] DETERMINISTIC --表示相同的输入参数总是产生[不同]相同的结果
| NO SQL --不包含SQL语句
| READS SQL DATA --包含读取数据的语句,如select
| MODIFIES SQL DATA -- 包含写入数据的语句,如update,delete


-- 存储函数调用语法
select 存储函数名称 ([参数列表]);

1.2. 示例

sql 复制代码
-- 使用存储函数实现
-- 传入一个 n, 计算从 1 到 n 累加的值

delimiter //
CREATE FUNCTION fun1(n INT) RETURNS INT
BEGIN
  -- 定义变量保存结果
  DECLARE total INT DEFAULT 0;
  -- 循环
   WHILE n > 0 DO
	SET total := total + n;
  SET n := n - 1;
END WHILE;

RETURN total;

END//

delimiter ;

-- 调用存储函数
SELECT fun1(100);

但是我们第一次运行就会出错,这是因为在 MySQL 8.0 版本中,如果 binlog 是开启的,那么在定义存储函数时,需要指定characteristic特 性,否则会报错。

sql 复制代码
-- 使用存储函数实现
-- 传入一个 n, 计算从 1 到 n 累加的值

delimiter //
CREATE FUNCTION fun1(n INT) RETURNS INT DETERMINISTIC
BEGIN
  -- 定义变量保存结果
  DECLARE total INT DEFAULT 0;
  -- 循环
   WHILE n > 0 DO
	SET total := total + n;
  SET n := n - 1;
END WHILE;

RETURN total;

END//

delimiter ;

-- 调用存储函数
SELECT fun1(100);

二、触发器

2.1. 触发器是什么

触发器是 MySQL 中与表强关联 的数据库对象,其核心是在对关联表执行 INSERT(插入)、UPDATE(更新)、DELETE(删除)三类特定操作时,自动触发并执行预先定义的 SQL 语句或逻辑块,无需手动调用,常用于实现数据验证、业务逻辑强制、操作日志记录等需求。就如同在点餐的时候,当用户向商家付钱时,就会触发商家记账的过程,而商家可以根据记账的信息判断自己需要进货、盈利还是亏损。

触发器的触发需满足 "触发时间 " 和 "触发操作" 两个条件:

  • 触发时间 :分为 BEFORE(操作执行前触发)和 AFTER(操作执行后触发),可根据业务需求选择(如数据校验适合 BEFORE,日志记录适合 AFTER)。
  • 触发操作:仅支持 INSERT、UPDATE、DELETE 三种表操作,即只有这三类操作能触发触发器。

通过 OLD 和 NEW 关键字可访问操作前后的数据,不同触发操作对应的关键字使用规则不同

|-------------|----------------|----------------|
| 触发器类型(触发操作) | OLD 关键字含义 | NEW 关键字含义 |
| INSERT 触发器 | 无(插入操作无 "旧数据") | 将要或已经插入的新数据 |
| UPDATE 触发器 | 数据更新前的旧值 | 将要或已经更新后的新值 |
| DELETE 触发器 | 将要或已经删除的旧数据 | 无(删除操作无 "新数据") |

触发器按 "触发粒度" 可分为行级触发器语句级触发器,二者的核心区别在于 "触发次数" 和 "数据访问能力":

类型 触发逻辑 数据访问能力 MySQL 支持情况
行级触发器 对表中每一行数据 执行操作时,均触发一次(如UPDATE语句影响 10 行,则触发 10 次) 可通过OLD/NEW访问当前行的新旧值 仅支持行级触发器
语句级触发器 整个 INSERT/UPDATE/DELETE 语句执行时,仅触发一次(无论影响多少行) 无法访问单条数据的新旧值,仅能处理全局逻辑 不支持

2.2. 语法

sql 复制代码
-- 创建
CREATE TRIGGER [IF NOT EXISTS] trigger_name
    trigger_time trigger_event
    ON tbl_name FOR EACH ROW
BEGIN
    trigger_stmt;
END;

trigger_time: { BEFORE | AFTER }

trigger_event: { INSERT | UPDATE | DELETE }

-- 查看
SHOW TRIGGERS;

-- 删除,如果没有指定schema_name,默认为当前数据库
DROP TRIGGER [IF EXISTS] [schema_name.]trigger_name;

2.3. 示例

sql 复制代码
-- 创建学生日志表
CREATE TABLE student_log (
  id BIGINT PRIMARY KEY auto_increment,
  operation_type VARCHAR(10) NOT NULL COMMENT '操作类型: INSERT/UPDATE/DELETE',
  operation_time DATETIME NOT NULL COMMENT '操作时间',
  operation_id BIGINT NOT NULL COMMENT '操作的记录ID',
  operation_data VARCHAR(500) comment '操作数据'
);
  • 插入数据的触发器
sql 复制代码
delimiter //
CREATE TRIGGER IF NOT EXISTS trg_student_insert
  AFTER INSERT ON student FOR EACH ROW
BEGIN
  -- 插入日志到 student_log 表
  INSERT INTO student_log (
    operation_type,
    operation_time,
    operation_id,
    operation_data
  ) VALUES (
    'INSERT',
    NOW(),
    new.id,
    CONCAT(new.id,',', new.name, ',', new.sno, ',', new.gender, ',', new.enroll_date, ',', new.class_id)
  );
  
END//

insert into student values (null, '曹操', '300001', 28, 1, '2025-09-01', 3);
  • 更新数据的触发器
sql 复制代码
delimiter //
CREATE TRIGGER IF NOT EXISTS trg_student_update
  AFTER UPDATE ON student FOR EACH ROW
BEGIN
  -- 插入日志到 student_log 表
  INSERT INTO student_log (
    operation_type,
    operation_time,
    operation_id,
    operation_data
  ) VALUES (
    'UPDATE',
    NOW(),
    new.id,
    CONCAT(old.id,',', old.name, ',', old.sno, ',', old.gender, ',', old.enroll_date, ',', old.class_id)
  );
  
END//

delimiter ;

update student set age = 20, class_id = 2 where name = '曹操'; 
sql 复制代码
-- 更新多条数据
update student set class_id = 3 where id >= 7; 
  • 删除数据的触发器
sql 复制代码
delimiter //
CREATE TRIGGER IF NOT EXISTS trg_student_delete
  AFTER DELETE ON student FOR EACH ROW
BEGIN
  -- 插入日志到 student_log 表
  INSERT INTO student_log (
    operation_type,
    operation_time,
    operation_id,
    operation_data
  ) VALUES (
    'DELETE',
    NOW(),
    old.id,
    CONCAT(old.id,',', old.name, ',', old.sno, ',', old.gender, ',', old.enroll_date, ',', old.class_id)
  );
  
END//

delimiter ;

delete from student where name = '曹操';
相关推荐
2401_882273721 分钟前
如何在 CSS 中正确加载本地 JPG 背景图片
jvm·数据库·python
曹牧32 分钟前
SQL:多个事务同时修改同一索引块
数据库·sql
aXin_ya34 分钟前
微服务第八天 Sentinel 四种分布式事务模式
java·数据库·微服务
Ruci ALYS36 分钟前
MySQL大小写敏感、MySQL设置字段大小写敏感
数据库·mysql
Lee川41 分钟前
Prisma 实战指南:像搭积木一样设计古诗词数据库
前端·数据库·后端
极创信息1 小时前
信创产品认证怎么做?信创产品测试认证的主要流程
java·大数据·数据库·金融·软件工程
lzhdim2 小时前
SQL 入门 12:SQL 视图:创建、修改与可更新视图
java·大数据·服务器·数据库·sql
2301_795099743 小时前
让 CSS Grid 自适应容器尺寸的动态布局方案
jvm·数据库·python
FQNmxDG4S3 小时前
Maven依赖管理:版本冲突解决与生命周期控制
java·数据库·maven