MySQL存储过程中需立即用SET变量保存ROW_COUNT()值,因它只反映最近DML影响行数且易被覆盖;应使用OUT参数传回客户端,事务中值在语句执行时即确定,不依赖提交。

MySQL 存储过程中怎么拿到 ROW_COUNT() 的值
执行完 INSERT、UPDATE 或 DELETE 后,ROW_COUNT() 立即返回上一条语句影响的行数——但它不是“自动保存”的,必须在下一条语句执行前读取,否则会被覆盖。
-
ROW_COUNT()是会话级函数,只反映当前连接中最近一次 DML 的结果,和存储过程是否被调用无关 - 不能在语句末尾直接加
SELECT ROW_COUNT();来“返回”给调用方;它只是查值,不传递 - 常见错误:在
UPDATE后隔了一条SET @x = 1;,再调ROW_COUNT(),结果变成 -1(表示语句没修改任何行,或被中间语句干扰) - 正确做法是立刻赋值给变量:
SET @affected = ROW_COUNT();
如何把影响行数传回客户端
存储过程本身不支持 RETURN 行数(像函数那样),必须靠输出参数或结果集。最常用、最稳妥的是 OUT 参数。
- 定义时声明:
OUT p_affected INT,调用时传入变量接收 - 赋值时机必须紧接在 DML 之后:
SET p_affected = ROW_COUNT(); - 如果过程里有多个 DML,
ROW_COUNT()只反映最后一条;要分别获取,就得在每条后立刻保存到不同变量 - 注意:如果 DML 是条件执行(比如
IF ... THEN UPDATE ... END IF;),且条件不满足,ROW_COUNT()返回 0,不是 NULL
ROW_COUNT() 在事务中的行为特点
它不关心事务是否提交,只看语句是否实际修改了数据行——哪怕在 ROLLBACK 前,它的值也已经确定。
- 事务内执行
UPDATE t SET x=1 WHERE id=999;(无匹配行),ROW_COUNT()立即为 0 - 接着执行
INSERT INTO t VALUES (1);,ROW_COUNT()变成 1;即使后面ROLLBACK,这个 1 仍是当时的真实计数 - 所以不能用它判断“最终是否生效”,只能说明“这条语句干了什么”
- 对
REPLACE或INSERT ... ON DUPLICATE KEY UPDATE,ROW_COUNT()可能返回 1(插入)或 2(先删后插)或 0(仅更新且值未变),行为比普通INSERT复杂
容易被忽略的兼容性细节
ROW_COUNT() 在 MySQL 5.7+ 和 8.0 行为一致,但和 PostgreSQL 的 GET DIAGNOSTICS、SQL Server 的 @@ROWCOUNT 不是完全等价概念。
- MySQL 中,
SELECT语句不改变ROW_COUNT()的值(返回 -1),但某些客户端驱动(如旧版 PHP mysqli)可能在执行SELECT后误报 0 - 使用
PREPARE/EXECUTE动态 SQL 时,ROW_COUNT()仍有效,但必须在EXECUTE后立刻读取 - 存储函数里不能用
ROW_COUNT()(因为函数禁止修改数据,而该函数设计上关联 DML),只能在存储过程或触发器中用
SET @r = ROW_COUNT();,而是它太容易被中间插入的任意语句抹掉——尤其在嵌套逻辑、异常处理或调试 SELECT 时,一不留神就拿错数。










