delete后立即执行select row_count()返回的是实际删除行数,而非where匹配数;若返回0,可能因条件未匹配、行已被删或类型转换失败,且中间不可穿插其他sql。

DELETE后直接查ROW_COUNT()就行
执行DELETE语句后,立刻调用SELECT ROW_COUNT(),返回的就是本次删除真正生效的行数。它不等于WHERE条件匹配的行数,而是实际从磁盘/缓冲区移除的记录条数。
常见错误现象:WHERE条件命中10行,但ROW_COUNT()返回0——说明这10行其实不存在(比如被其他事务提前删了),或表为空、条件写错、字段类型隐式转换失败导致没匹配上。
- 必须紧接在
DELETE之后执行,中间不能穿插其他SQL(哪怕是个SELECT 1也会重置计数) - 在存储过程中也适用,但要注意嵌套语句里上一层的
ROW_COUNT()会被覆盖 - 如果
DELETE带LIMIT,返回值就是实际删掉的行数,不会超过LIMIT值
mysql_affected_rows()在客户端代码里怎么用
PHP、Python(PyMySQL)、Java(JDBC)等驱动都提供类似mysql_affected_rows()的接口,本质是读取协议层返回的“affected rows”字段,和ROW_COUNT()语义一致。
容易踩的坑:
- PHP中
mysqli_affected_rows($link)必须传入连接句柄,不能省略;PDO则用$stmt->rowCount() - 事务中必须在
DELETE后立即获取,COMMIT或ROLLBACK之后就失效了 - 某些ORM(如Django ORM)默认不暴露原生影响行数,得用
cursor.execute("DELETE ..."); cursor.rowcount绕过
为什么DELETE FROM t返回0而不是总行数
这是MySQL明确规定的:无WHERE条件的全表删除,ROW_COUNT()返回0,哪怕表里有100万行。
原因在于MySQL优化器对这类操作做了特殊处理,不逐行计数,而是直接清空数据页。所以不能靠它判断是否真删了数据。
- 想确认是否清空成功,改用
SELECT COUNT(*) FROM t查剩余行数 - 生产环境严禁裸写
DELETE FROM t,务必加WHERE或先用SELECT预估范围 -
TRUNCATE TABLE t也返回0,且无法回滚,行为更激进
UPDATE/INSERT也能用ROW_COUNT(),但逻辑不同
ROW_COUNT()对不同语句含义不统一,容易误判:
-
UPDATE:只统计“字段值实际发生变化”的行数(比如SET name='a'但原值就是'a',不算) -
INSERT ... ON DUPLICATE KEY UPDATE:冲突时更新返回1,无冲突插入返回1,冲突+更新返回2 -
REPLACE INTO:删除旧行+插入新行,总共影响2行时返回2 -
INSERT IGNORE:插入成功返回1,冲突跳过返回0
所以别假设ROW_COUNT()总是等于WHERE匹配数——它反映的是存储引擎层面的真实变更量,不是语法层面的“应该变更多少”。











