news 2026/8/14 16:38:28

MySQL存储过程与触发器实战技巧

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
MySQL存储过程与触发器实战技巧

存储过程:

USE my_suoyin_learning; DELIMITER // CREATE PROCEDURE p11(IN uage INT) BEGIN -- 第1层:普通变量 DECLARE uname VARCHAR(100); DECLARE upro VARCHAR(100); DECLARE done INT DEFAULT 0; -- 第2层:游标(必须放在handler之前) DECLARE u_cursor CURSOR FOR SELECT username,job FROM user_info WHERE age<=uage; -- 第3层:NOT FOUND异常处理器(最后写) DECLARE CONTINUE HANDLER FOR NOT FOUND SET done = 1; -- 创建目标表 CREATE TABLE IF NOT EXISTS tb_user_pro( id INT PRIMARY KEY AUTO_INCREMENT , NAME VARCHAR(100), profession VARCHAR(100) ); OPEN u_cursor; WHILE done = 0 DO FETCH u_cursor INTO uname,upro; IF done = 0 THEN INSERT INTO tb_user_pro VALUES(NULL, uname, upro); END IF; END WHILE; CLOSE u_cursor; END // DELIMITER ; CALL p11(23); SELECT * FROM tb_user_pro;
一次性修正全套代码 1、先删掉旧触发器 sql DROP TRIGGER IF EXISTS tb_user_insert_trigger; 2、重新创建日志表(统一字段名) sql CREATE TABLE IF NOT EXISTS user_logs ( id INT PRIMARY KEY AUTO_INCREMENT COMMENT '日志编号', uid INT COMMENT '新增用户ID', operate_time DATETIME COMMENT '操作时间', action VARCHAR(50) COMMENT '操作类型' ); 3、重新创建触发器(字段严格匹配) sql DELIMITER // CREATE TRIGGER tb_user_insert_trigger AFTER INSERT ON user_info FOR EACH ROW BEGIN INSERT INTO user_logs(uid, operate_time, action) VALUES(NEW.id, NOW(), '新增用户'); END // DELIMITER ; 4、再次执行插入测试 sql INSERT INTO user_info(id,username,phone) VALUES(10,'张三','123456'); 5、查看日志是否写入成功 sql SELECT * FROM user_logs; 补充:如果你就想用 operation 这个字段名 把建表和触发器统一改成 operation: sql DROP TABLE IF EXISTS user_logs; CREATE TABLE user_logs ( id INT PRIMARY KEY AUTO_INCREMENT, uid INT, operate_time DATETIME, operation VARCHAR(50) ); DELIMITER // CREATE TRIGGER tb_user_insert_trigger AFTER INSERT ON user_info FOR EACH ROW BEGIN INSERT INTO user_logs(uid, operate_time, operation) VALUES(NEW.id, NOW(), '新增用户'); END // DELIMITER ; 核心规则:INSERT 括号里的字段名,必须和数据表真实字段完全一模一样,一字不差。

触发器总结:

两段触发器代码完整解析

整体说明

你现在写了两个触发器:

  1. 新增触发器:给tb_user插入数据之后,自动往日志表user_logs记录插入详情

  2. 删除触发器:给tb_user删除数据之后,自动往日志表user_logs记录删除前的数据 用到两个关键字:

  • NEW:INSERT/UPDATE 触发时,代表新增 / 修改后的新数据行

  • OLD:DELETE/UPDATE 触发时,代表删除 / 修改前的旧数据行


第一段:插入触发器 tb_user_insert_trigger

sql

create trigger tb_user_insert_trigger after insert on tb_user for each row begin insert into user_logs(id, operation, operate_time, operate_id, operate_params) VALUES (null, 'insert', now(), new.id, concat('插入的数据内容为: id=',new.id,',name=',new.name, ', phone=', NEW.phone, ', email=',new.email)); end;

逐行拆解

  1. create trigger tb_user_insert_trigger创建触发器,名字:tb_user_insert_trigger

  2. after insert on tb_user for each row

  • after insert插入 tb_user 数据完成之后再执行触发器

  • for each row:每插入一行数据,就触发一次

  1. begin ... end:触发器要执行的 SQL 逻辑体

  2. 内部插入日志逻辑:

sql

insert into user_logs(字段) values(值)

表格

字段

填入内容

含义

id

null

日志主键自增,填 null 自动生成

operation

'insert'

操作类型:新增

operate_time

now()

当前系统时间

operate_id

new.id

本次新增用户的 id(NEW = 刚插入的新行数据)

operate_params

concat 拼接字符串

把本次插入的所有字段打包成文本存起来

触发场景

执行插入语句:

sql

INSERT INTO tb_user(id,name,phone,email) VALUES(1,'张三','13800138000','zs@qq.com');

tb_user 插入成功瞬间,自动在user_logs生成一条插入日志。


第二段:删除触发器 tb_user_delete_trigger

sql

create trigger tb_user_delete_trigger after delete on tb_user for each row begin insert into user_logs(id, operation, operate_time, operate_id, operate_params) VALUES (null, 'delete', now(), old.id, concat('删除之前的数据: id=',old.id,',name=',old.name, ', phone=', old.phone, ', email=', old.email, ', profession=',old.profession)); end;

重点区别

  1. after delete on tb_user:删除 tb_user 数据之后触发

  2. 必须用 OLD 关键字删除操作数据已经没了,只能用OLD获取删除前原本存在的整条数据

  3. operation = 'delete':标记本次操作为删除

  4. concat 把删除前所有字段拼接保存,方便后期回溯找回删掉的数据

触发场景

执行删除语句:

sql

DELETE FROM tb_user WHERE id=1;

数据删掉之后,自动写入一条删除日志,留存删除前完整信息。


配套查看命令

1. 查看当前库所有触发器(你执行的 show triggers;)

sql

show triggers;

运行后表格会列出:触发器名称、触发时机、绑定表、触发语句等信息,能验证两个触发器都创建成功。

2. 查看日志记录(验证触发器有没有生效)

sql

SELECT * FROM user_logs;

插入、删除数据后执行这条语句,就能看到自动生成的操作日志。

3. 删掉触发器(写错需要重建时)

sql

DROP TRIGGER IF EXISTS tb_user_insert_trigger; DROP TRIGGER IF EXISTS tb_user_delete_trigger;

关键知识点总结

  1. 时机after insert/delete:数据操作完毕再记日志;一般日志都用 after

  2. 新旧行关键字

  • 新增:只有NEW,没有 OLD

  • 删除:只有OLD,没有 NEW

  • 修改:NEW(新数据)+ OLD(旧数据)都能用

  1. concat():MySQL 字符串拼接函数,把多个文本、字段拼成一整条日志详情

注意你的代码小隐患

你没有写DELIMITER改结束符,在 Navicat/DataGrip 里大概率会报语法错误。

标准完整可运行写法示例

sql

DELIMITER // create trigger tb_user_insert_trigger after insert on tb_user for each row begin insert into user_logs(id, operation, operate_time, operate_id, operate_params) VALUES (null, 'insert', now(), new.id, concat('插入的数据内容为: id=',new.id,',name=',new.name, ', phone=', NEW.phone, ', email=',new.email)); end // DELIMITER ;

先把语句结束符临时改成//,避免触发器内部的;截断整段创建语句,创建完再改回默认;

需要我给你一套完整测试 SQL(插入→删除→查看日志),你直接复制运行看效果吗?

和你刚刚写的区别在哪里

新旧两套触发器核心区别

一、最直观的 5 处差异

1. 日志存储内容复杂度不一样

我最开始给你的版本: 只简单记录:操作人 ID、时间、操作文字(新增用户),内容极简

sql

INSERT INTO user_logs(uid, operate_time, action) VALUES(NEW.id, NOW(), '新增用户');

你现在这套: 把整条插入 / 删除的所有字段全部拼接打包存下来concat()拼接 id、姓名、电话、邮箱、职业完整详情,日志更详细,方便后期回溯数据

sql

concat('插入的数据内容为: id=',new.id,',name=',new.name, ', phone=', NEW.phone, ', email=',new.email)

2. 字段命名完全不同

我初始日志表字段:id、uid、operate_time、action

你自定义日志表字段:id、operation(操作类型)、operate_time(时间)、operate_id(用户id)、operate_params(完整参数详情)字段命名更贴合开发规范。

3. 新增了【删除触发器】

我一开始只写了INSERT 插入触发器你现在做了两套完整闭环:

  • 插入后记录日志

  • 删除后记录删除前原始数据日志 覆盖了新增、删除两种数据库操作场景。

4. 新旧关键字使用区分(核心语法区别)

1)插入场景: 两者都只用NEW(新数据),无区别 2)删除场景: 只能用OLD

  • OLD.id/ OLD.name:代表删掉之前原本存在的数据删除之后数据已经从表消失,只能靠 OLD 读取历史内容,这是新增触发器没有的语法点。

5. 语法细节:结束符 DELIMITER 问题

我最初完整示例里特意加了DELIMITER //修改语句终止符:

sql

DELIMITER // 触发器内容 end // DELIMITER ;

作用:防止触发器内部的分号;提前截断创建语句,避免 1064 语法报错; 你截图里的代码没有加这段,在命令行 MySQL 里会直接语法报错,DataGrip 可视化工具做了兼容暂时没报错,但标准写法必须带上。

二、功能层面区别总结

表格

版本

支持操作

日志内容

适用场景

我最初简易版

仅插入 INSERT

极简记录:用户 ID + 时间 + 操作文字

初学理解触发器原理

你现在完整版

插入 INSERT + 删除 DELETE

完整存储整条数据详情

项目真实审计日志、数据恢复场景

三、额外小知识点

后续你还可以继续拓展UPDATE 修改触发器: 修改数据时,可以同时用OLD(修改前旧数据)+NEW(修改后新数据),记录数据前后变化。

四、查看日志的方式没有变化

无论日志内容简单还是详细,查看语句始终一致:

sql

SELECT * FROM user_logs;

执行后就能看到插入、删除自动生成的全部操作记录。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/8/14 16:26:48

Vue 3 学习笔记:从入门到核心概念

一、Vue 3 简介与优势 Vue 3 是 Vue.js 框架的重大版本更新&#xff0c;于 2020 年 9 月正式发布。它带来了全新的 Composition API、更好的 TypeScript 支持、更小的打包体积以及更高的性能。 主要优势&#xff1a; Composition API&#xff1a;提供更灵活的逻辑复用方式&a…

作者头像 李华
网站建设 2026/8/14 16:21:30

继承体系搭好了,方法找不到了

系列回顾:上一篇毛毛姐叠了三个装饰器,执行顺序全反了——洋葱模型 + 协议覆盖,元编程的两把双刃剑。这一篇,毛毛姐搭了个粉丝管理的多重继承体系,结果方法调用顺序完全不对。 📋 本期坑点速览:多重继承 MRO 顺序反直觉 super() 在闭包中绑定错误类 __name 名称修饰不…

作者头像 李华
网站建设 2026/8/14 16:20:36

06-指标自动抽取-从影像和数仓到AI特征向量

指标自动抽取&#xff1a;从影像和数仓到 AI 特征向量 前言 指标是连接"原始数据"和"AI 推理"的关键桥梁。在上一篇文章中&#xff0c;我们讨论了 AI 如何从非结构化材料中提取字段。但这些字段本身不是指标——字段是"投保人年龄 35"&#x…

作者头像 李华
网站建设 2026/8/14 16:18:43

网页视频下载开源利器:猫抓插件从安装到批量获取全指南

网页视频下载开源利器&#xff1a;猫抓插件从安装到批量获取全指南 【免费下载链接】cat-catch 猫抓 浏览器资源嗅探扩展 / cat-catch Browser Resource Sniffing Extension 项目地址: https://gitcode.com/GitHub_Trending/ca/cat-catch 那个周三下午&#xff0c;插画师…

作者头像 李华
网站建设 2026/8/14 16:18:41

人工智能学院科协26公招

人工智能学院科协公招“搭好台子&#xff0c;唱好戏——我们既是幕后人&#xff0c;也可以是台上人。”一、科协是什么&#xff1f; 科协全称“科技协会”&#xff0c;是学院学术科技活动的服务与支持团队。我们的核心使命是&#xff1a; 组织与保障&#xff1a;策划并执行院内…

作者头像 李华