存储过程必须显式调用,触发器在INSERT/UPDATE/DELETE时自动执行;前者用CALL调用并支持参数,后者无调用语法、依赖事件且可访问NEW/OLD等隐式数据。

存储过程必须显式调用,触发器在 INSERT/UPDATE/DELETE 事件发生时自动执行 —— 这是最核心、最不可绕开的区别。
调用方式:CALL vs 隐式触发
存储过程像一个函数,得你主动喊它干活:CALL proc_name('arg1', 'arg2') 或 EXEC proc_name。不调,它就安静待着。触发器没有名字可调,你写完 CREATE TRIGGER tr_log ON users AFTER INSERT,之后只要对 users 表执行 INSERT,它就立刻跑起来,连事务都裹在里面。
常见错误现象:有人试图用 CALL tr_log 调用触发器,报错 Unknown routine 'tr_log' —— 触发器根本不支持显式调用。
- 存储过程可被应用层、定时任务、另一个存储过程反复调用
- 触发器只响应绑定表的三类操作(
INSERT/UPDATE/DELETE),且只能绑定到一张表(MySQL)或视图(SQL Server) - 触发器无法传参,但能通过
inserted(SQL Server)或NEW(MySQL)访问刚变更的数据行
参数与数据访问:有无输入参数 + 临时表可用性
存储过程可以定义 IN、OUT、INOUT 参数,比如 CREATE PROCEDURE calc_bonus(IN emp_id INT, OUT bonus DECIMAL);触发器没有参数声明语法,全靠隐式上下文。
但触发器有存储过程没有的“现场数据”:NEW 和 OLD(MySQL)或 inserted/deleted(SQL Server)这些只读临时表,让你能拿到刚插入的值、被删前的旧状态。存储过程想查这些,得自己写 SELECT 去捞。
- 想做金额校验?触发器里直接
IF NEW.amount - 想把用户注册信息同步到日志表?触发器里
INSERT INTO user_log SELECT NEW.*;就完事 - 存储过程若要做同样事,得先
SELECT出来再处理,多一次查询开销
事务行为:嵌套层级与回滚影响
触发器默认运行在触发它的 SQL 语句所属的同一个事务中。也就是说,如果触发器里 INSERT 失败,整个原始 INSERT 也会一起回滚 —— 它不是独立事务。
存储过程则灵活得多:可以用 START TRANSACTION 自己开事务,也可以选择不开启,完全由调用方控制事务边界。
- 误在触发器里加
COMMIT?MySQL 会直接报错Can't execute statement in a READ ONLY transaction - 触发器里抛异常(如
SIGNAL)会导致原始操作失败,这是强制数据一致性的关键机制 - 存储过程里
ROLLBACK只影响它自己开启的事务,不影响外层调用者
真正容易被忽略的是时机粒度:MySQL 的触发器只支持 BEFORE 和 AFTER,不支持 INSTEAD OF;而 SQL Server 支持三者,INSTEAD OF 甚至能拦截并替代原操作 —— 这种差异直接影响能否在视图上实现更新逻辑。别默认所有数据库行为一致。

















