declare变量仅在触发器begin…end块内有效,每次触发时重新声明、初始化并销毁,与其他触发器及会话变量完全隔离,不可跨语句或跨触发器复用。

触发器中DECLARE变量只在BEGIN…END块内有效
MySQL触发器里的DECLARE变量是局部变量,作用域严格限定在触发器体的BEGIN和END之间。它不能被同表其他触发器访问,也不能在触发器外部(比如会话里)用@var或直接引用。
常见错误现象:Unknown column 'my_var' in 'field list' 或 Undeclared variable,往往是因为在END之后还试图使用该变量,或在另一个触发器里复用同名变量——它们彼此完全隔离。
- 变量声明必须放在
BEGIN后、任何其他语句前(包括SET、IF等) - 同一触发器中多次
DECLARE同名变量会报错:Redeclaring identifier - 不同触发器(哪怕在同一张表上)可以声明同名变量,互不影响
DECLARE变量生命周期止于触发器执行结束
每次触发器被调用时,DECLARE变量都会重新分配内存、初始化(如果有DEFAULT)、执行赋值;触发器执行完,变量立即销毁,不保留状态。它不像用户变量@var那样跨语句存活。
使用场景举例:你在BEFORE INSERT触发器里用DECLARE dept_id INT DEFAULT 0做逻辑判断,插入100行就会创建并销毁100次该变量——没有累积、没有残留。
- 不会因事务回滚而“恢复旧值”,因为变量本身不参与事务日志
- 不能用
SELECT ... INTO以外的方式给DECLARE变量赋初值(比如不能SET var = (SELECT ...)后再DECLARE) -
DEFAULT子句只在声明时生效一次,后续SET覆盖后不再自动重置
别把DECLARE变量和@用户变量混用
这是最容易踩的坑:DECLARE变量和会话级用户变量@var名字可以一样,但完全是两套机制。在触发器里写SET @counter = @counter + 1,这个@counter是会话级的,可能被其他SQL污染;而DECLARE counter INT DEFAULT 0每次都是干净的。
性能影响很小,但语义风险极高——尤其在并发插入时,@变量会成为共享状态,导致逻辑错乱;DECLARE变量则天然线程安全(每个触发器调用独享一份)。
- 触发器里禁止对
DECLARE变量使用@前缀(语法报错:Variable '@xxx' must be declared) -
SELECT ... INTO只能赋值给DECLARE变量,不能用于@变量(后者要用SET @x := (SELECT ...)) - 调试时用
SELECT查@变量能看到值,但查DECLARE变量会提示Unknown column
触发器嵌套时DECLARE变量不跨层传递
MySQL不支持触发器调用另一个触发器,所以不存在“嵌套作用域”问题。但要注意:如果一个表上有多个触发器(比如BEFORE INSERT和AFTER INSERT),它们各自DECLARE的变量完全独立,无法传递值。
想在BEFORE和AFTER之间传数据,唯一可靠方式是通过临时表、用户变量@(需谨慎并发)、或修改NEW字段本身(仅限BEFORE可写)。
-
NEW和OLD不是变量,是只读/只写伪记录,不能DECLARE重名覆盖 - 试图在
AFTER触发器里DECLARE一个和BEFORE同名变量,不会继承值,而是全新实例 - 所有
DECLARE语句必须显式写出类型,MySQL不推断(比如不能DECLARE x DEFAULT 1而不写类型)
DECLARE变量看着简单,但它的“每次新建、用完即弃”特性,恰恰是最容易被当成普通变量误用的地方——尤其当逻辑从存储过程搬进触发器时,习惯性加@或指望跨语句复用,结果值就丢了。











