MariaDB存储过程创建触发器及非存储过程SQL异常处理咨询
MariaDB运维脚本问题解答
1. 存储过程内部创建触发器的实现方案
MariaDB 10.2及以上版本支持在存储过程内部通过预处理动态SQL的方式创建/修改触发器,绕过原生不允许直接在存储过程中写CREATE TRIGGER语句的限制。
实现示例:
DELIMITER // CREATE PROCEDURE TASK_CREATE_TRIGGER(OUT RESULT BOOLEAN) BEGIN DECLARE EXIT HANDLER FOR SQLEXCEPTION BEGIN SELECT 'Error running TASK_CREATE_TRIGGER'; SHOW ERRORS; SET RESULT=FALSE; END; -- 拼接触发器创建SQL,注意字符串内部单引号需要转义(写两个单引号) SET @trigger_ddl = ' CREATE TRIGGER trg_user_after_update AFTER UPDATE ON user_info FOR EACH ROW BEGIN INSERT INTO op_log(table_name, op_type, op_time, operator) VALUES(''user_info'', ''update'', NOW(), CURRENT_USER()); END'; -- 预处理并执行DDL PREPARE stmt FROM @trigger_ddl; EXECUTE stmt; DEALLOCATE PREPARE stmt; SET @trigger_ddl = NULL; SET RESULT=TRUE; END // DELIMITER ;
之后可以把这个存储过程直接加入RUN_TASKS的执行队列,和其他任务存储过程保持一致的错误处理逻辑,遇到异常会自动终止后续任务。
注意:如果你的MariaDB版本低于10.2,动态SQL方案不生效,只能将触发器创建逻辑放到存储过程外部执行。
2. 存储过程外部的SQL异常处理实现方案
MariaDB原生没有提供客户端SQL层面(即存储过程/函数/触发器之外的执行上下文)的TRY/CATCH或异常声明语法,DECLARE HANDLER仅支持在存储程序内部使用,外部异常处理必须依托SQL的调用端实现,常见生产可用方案如下:
- 方案1:通过命令行客户端参数+外层调度脚本实现错误终止
运维场景下绝大多数SQL脚本都是通过shell、Ansible等调度工具执行,直接在调度层判断每段SQL的执行返回码即可实现异常拦截:- 调用
mysql命令行客户端时添加--stop-on-error参数,客户端遇到SQL报错会立刻终止执行,不会继续运行后续语句 - 可以直接通过shell脚本分段执行SQL,判断每段的退出状态码,非0则直接终止流程、输出错误日志
调度脚本示例:
如果需要事务保证,可以在SQL脚本开头添加#!/bin/bash MYSQL_CLI="/usr/bin/mysql -u运维账号 -p'你的密码' 业务库名" # 执行原有任务存储过程 $MYSQL_CLI -e "CALL RUN_TASKS();" if [ $? -ne 0 ]; then echo "存储过程任务执行失败,终止后续流程" exit 1 fi # 执行触发器创建语句 $MYSQL_CLI -e " CREATE TRIGGER trg_user_after_update AFTER UPDATE ON user_info FOR EACH ROW BEGIN INSERT INTO op_log(table_name, op_type, op_time, operator) VALUES('user_info', 'update', NOW(), CURRENT_USER()); END;" if [ $? -ne 0 ]; then echo "触发器创建失败,流程终止" exit 1 fi echo "所有运维任务执行完成" exit 0SET autocommit=0;,所有任务执行完成后再执行COMMIT;,流程异常终止时未提交的事务会自动回滚,保证数据一致性。 - 调用
- 方案2:全逻辑收拢到存储过程
如果不想依赖外层调度工具,就把所有需要执行的DDL(包括触发器创建、修改)全部通过前文提到的动态SQL方式包装成独立的任务存储过程,全部加入RUN_TASKS的执行链,完全复用已有的存储过程异常处理逻辑,不需要在SQL外层做任何异常捕获。
内容的提问来源于stack exchange,提问作者denver
相关产品推荐
相关产品推荐

