MySQL性能:存储过程+触发器基础实战攻略
MySQL性能:存储过程+触发器基础实战攻略
一、MySQL中的存储过程
1.基础概念
1.1 什么是存储过程?
-
定义:存储过程是预编译的SQL语句的集合,存储在数据库中,通过传递参数执行,可封装复杂业务逻辑,提升执行效率
-
优势:
- 减少网络交互(单词调用代替多次SQL传输)
- 编译一次,重复调用无需重新编译
- 通过权限控制增强数据安全性
1.2基本语法
-- 创建存储过程
DELIMITER $$ -- 修改结束符避免冲突
CREATE PROCEDURE procedure_name(参数列表)
BEGIN
SQL语句;
END $$
DELIMITER ; -- 恢复默认结束符
-- 调整存储过程
CALL procedure_name(参数);
-- 删除存储过程
DROP PROCEDURE IF EXISTS procedure_name;
2.参数与变量
2.1 参数类型
类型 | 说明 | 示例 |
---|---|---|
IN | 输入参数(类型) | IN user_id INT |
OUT | 输出参数 | OUT total_sales DECMAL |
INOUT | 双向参数(可输入输出) | INOUT counter INT |
2.2 变量使用
-
用户变量:以
@
开头,当前会话有效SET @var_name = 100; --赋值 SELECT @var_name; --查看
-
局部变量:需要
DECLARE
声明,仅在BEGIN/END块内有效
3.流程控制
3.1 条件语句(两种)
-- 基础语法:IF-THEN-ELSE
IF CONDITION THEN
statements;
ELSEIF another_condition THEN
statements;
ELSE
statements;
END IF;
-- CASE 语句 CASE-WHEN
CASE variale
WHEN value1 THEN statements;
WHEN value1 THEN statements;
ELSE statements;
END CASE;
3.2 循环语句
循环类型 | 特点 | 示例 |
---|---|---|
WHILE | 先判断后执行 | WHILE i < 10 DO ... END WHILE; |
LOOP | 至少执行一次,需配合LEAVE退出 | loop_label: LOOP ... IF exit_condition THEN LEAVE loop_label; END IF; END LOOP; |
REPEAT | 先执行后判断 | REPEAT ... UNTIL condition END REPEAT; |
-
WHILE
WHILE I<10 DO statements; END WHILE;
-
loop
loop_label: loop ... IF condition THEN LEAVE loop_labe; END IF; END Loop;
-
REPEAT
REPEAT ... UNTIL condition END REPEAT
4.游标与异常处理
4.1 游标
-
作用:用于逐行处理查询结果集,适用于复杂数据处理场景
DECLARE cur CURSOR FOR SELECT colum FROM table; -- 声明游标 OPEN cur; -- 打开游标 FETCH cur INTO @var; -- 获取数据到变量 CLOSE cur; -- 关闭游标 DEALLOCATE cur; -- 释放游标
4.2 异常处理
-
作用:通过
DECLARE HANDLER
捕获错误,确保事务完整性DECLARE EXIT HANDLER FOR SQLEXCEPTION -- 获取SQL异常 BEGIN ROLLBACK; -- 回滚事务 SELECT 'Error occurred, transaction rolled back'; END;
-
DECLAER ...HANDLER
:捕获指定条件,并以处理逻辑-
条件类型:
-
SQLEXCEPTION
:SQL错误(如约束冲突) -
SQLWARING
:警告 -
NOT FOUND
:无匹配记录(常见于游标)
-
-
-
处理程序类型:
EXIT HANDLER
:执行处理后退出当前代码块CONTINUE HANDLER
:执行处理后继续执行后续代码
5.综合案例
5.1 用户注册存储过程
-- 用户从前端输入数据,传输到后端,我只需要进行存储。 相当于MysQL中的输入,输入成功后,我们需要返回结果!
DELIMITER $$
CREATE PROCEDURE RegisterUser(
IN p_username VARCHAR(50)
IN P_email VARCHAR(100),
OUT P_result VARCHAR(100)
)
BEGIN
DECLARE user_exists INT DEFAULT 0;
-- 检查用户名是否存在
SELECT COUNT(*) INTO user_exists
FROM users
WHERE username = p_username;
IF user_exists > 0 THEN
SET p_result = 'Username already exists';
ELSE
INSERT INTO users(username, email)
VALUES (p_username,p_email);
SET p_result = 'Registration successful';
END IF;
END $$
DECLARE ;
-- 调用示例
CALL RegisterUser('alice','alice@example.com',@result);
SELECT @result; -- 结果
5.2使用游标遍历数据
DELIMITER $$
CREATE PROCEDURE ProcessUsers()
BEGIN
DECLARE done INT DEFAULT FALSE;
DECLARE user_id INT;
DECLARE user_name VARCHAR(50);
-- 声明游标
DECLARE cur CURSOR FOR SELECT id,name FROM user;
-- 异常处理:未找到数据时退出循环
DECLARE CONTINUE HANDLER FOR NOT FOUND SET done = True;
OPEN cur;
read_loop:LOOP
FETCH cur INTO user_id,user_name;
IF done THEN
LEVEL read_loop;
END IF;
-- 处理每一行数据(打印)
SELECT CONCAT('ID:',user_id, ',name:',user_name);
END LOOP;
CLOSE cur;
END $$
DELIMITER ;
-- 调用示例
CALL ProcessUsers()
二、MYSQL中的触发器
1.基础概念
1.1 什么是触发器
触发器(Trigger)是数据库中的一种特殊对象,当指定事件(插入、更新、删除)在表中发生时自动执行一段预定义的SQL代码。
-
触发时机:BEFORE 操作前 或AFTER 操作后
-
行级触发:对每一条受影响的数据行触发(MySQL 仅支持行级触发)
-
核心用途:数据验证、审计跟踪、自动维护衍生数据(统计字段)、强制业务规则
1.2 基本语法
CREATE TRIGGER trigger_name
{BEFORE | AFTER} {INSERT |UPDATE |DELETE}
ON table_name FOR EACH ROW
BEGIN
-- 触发器的逻辑(使用NEW 和 OLD访问数据)
END;
1.3 触发器的逻辑
访问旧数据和新数据
OLD
: 引用被更新或删除的旧数据(UPDATE/DELETE
可用)NEW
:引用插入或更新后的新数据(INSERT/UPDATE
可用)
2.案例
2.1 审计日志
记录用户表的变更
-- 创建审计表
CREATE TABLE user_audit(
id INT AUTO_INCREMENT PRIMARY KEY,
user_id INT,
old_name VARCHAR(50),
new_name VARCHAR(50),
change_time TIMESTAMP
);
-- 创建AFTER UPDATE 触发器
DELIMITER $$
CREATE TRIGGER after_user_update
AFTER UPDATE
ON users FOR EACH ROW
BEGIN
INSERT INTO user_audit (user_id, old_name, new_name, change_time)
VALUES (OLD.id, OLD.name, NEW.name, NOW());
END $$
DELIMITER ;
2.2 数据验证与约束
阻止不合法的数据插入(BEFORE INSERT)
DELIMITER $$
CREATE TRIGGER before_employees_insert
BEFORE INSERT
ON emloyees FOR EACH ROW
BEGIN
IF NEW.salary < 3000 THEN
SIGNAL SQLSTATE '45000'
SET MESSAGE_TEXT = 'Salary cannot be less than 3000'
END IF;
END $$
DELIMITER ;
-
SIGNAL
:MySQL中用于"返回"错误或警告信息的语句。 它允许开发者在存储过程中,函数或触发器中,根据特定的条件生成自定义的错误或警告信息。 -
SQLSTATE
: 用于SQL操作状态的标准代码,它用于指示错误的类型或警告的性质-- 基础语法: SIGNAL SQLSTATE 'sqlstate_value' SET MESSAGE_TEXT = 'message' -- 可选 字符串,提供详细的错误信息或警告信息 SET MSYQL_ERRNO = 'error_code' -- 可选 整数,用于表示MySQL的错误代码
2.3 自动维护衍生数据
更新订单总金额同时同步用户消费总额(订单总金额,用户消费总金额
DELIMITER $$
CREATE TRIGGER after_order_update
AFTER UPDATE
ON order FOR EACH ROW
BEGIN
UPDATE users
SET total_spent = total_spent + (NEW.amount - OLD.amount)
WHERE id = NEW.user_id;
END $$
DELIMITER;
3.触发器的执行顺序与限制
- 执行顺序:同一表的同一事件触发时,按照触发器创建的是顺序执行
- 限制:
- 不能再触发器对本表执行
INSERT/UPDATE/DELETE
- 触发器不能调用存储过程或动态SQL
- 不支持显示事务控制(commit/rollback)
- 不能再触发器对本表执行
4.触发器的管理命令
4.1查看触发器
-- 查看触发器
SHOW TRIGGER FROM database_name;
-- 或查询information_schema
SELECT * FROM information_schema.triggers
WHERE trigger_schema = 'database_name';
4.2删除触发器
DROP TRIGGER [IF EXISTS] database_name.trigger_name;
5.适用场景
- 适用:
- 审计日志、数据版本跟踪。
- 简单字段级校验或自动填充(如更新时间戳)。
- 维护冗余统计字段(需权衡一致性)。
- 不适用:
- 复杂业务逻辑(优先用应用层代码)。
- 高频交易场景(如每秒数千次写入)。
- 需要跨数据库操作的场景。
6.注意事项
- 性能影响:高频写操作的表避免复杂触发器逻辑
- 可维护性:触发器逻辑应简单清洗,比卖你隐藏业务规则
- 错误处理:触发器中的错误会导致主操作回滚(如SIGNAL)
- 权限要求:创建触发器需要TRIGGER权限
- 测试:确保触发器和主操作在事务中协同工作