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 = '曹操';
相关推荐
tyatyatya5 分钟前
MySQL Group Replication(MGR)集群部署,实现自动故障切换
数据库·mysql
b***59435 分钟前
mysql 迁移达梦数据库出现的 sql 语法问题 以及迁移方案
数据库·sql·mysql
木风小助理6 分钟前
MySQL中COUNT()、COUNT(1)与COUNT
数据库
不想上班的小吕6 分钟前
采购申请创建(BAPI_PR_CREATE/BAPI_REQUISITION_CREATE)
java·服务器·数据库
j***89468 分钟前
MySQL官网驱动下载(jar包驱动和ODBC驱动)【详细教程】
数据库·mysql
emma羊羊9 分钟前
Vulhub-Mysql靶场
数据库·mysql
橘橙黄又青15 分钟前
mongodb的基本命令
数据库·mongodb
AC赳赳老秦18 分钟前
量化交易脚本开发:DeepSeek生成技术指标计算与信号触发代码
数据库·elasticsearch·信息可视化·流程图·数据库架构·memcached·deepseek
何中应20 分钟前
Redis的两个小错误
数据库·redis·缓存
Dovis(誓平步青云)35 分钟前
《Linux 核心 IO 模型深析(中篇):探索Cmake与多路转接的高效实现poll》
linux·运维·服务器·数据库·csdn成长记录