两个口径是什么
执行 INSERT/UPDATE/DELETE 后拿到的受影响行数,其实有两套口径。MySQL 默认返回 changed:只有值真的发生变化才计数,把行改成和原来一样则计 0;连接层带上 CLIENT_FOUND_ROWS 标记后返回 found(匹配到的行数),匹配即计数。PostgreSQL 返回匹配并处理的行数,值相同也照样计数。
基本信息
| MySQL 默认 | changed 口径:值发生变化的行才计数 |
|---|---|
| MySQL found 口径 | 需连接带上 CLIENT_FOUND_ROWS 标记 |
| PostgreSQL | 返回匹配并处理的行数,值相同也计数 |
| 取值方式 | MySQL 用客户端 affected_rows 或 ROW_COUNT();PG 用命令标签或 GET DIAGNOSTICS |
| 典型用途 | 幂等脚本判断存在性、判断是否真的发生变更 |
典型使用场景
- 幂等脚本判断记录是否存在:需要 found 口径(匹配即计数)
- 判断是否真的发生变更以决定后续动作:需要 changed 口径
- 乐观锁与版本号校验:期望受影响行数等于 1,多了少了都说明并发异常
- 数据修复脚本核对命中行数,确认改动范围符合预期
- 批量迁移统计进度:口径统一后进度才可信
MySQL 写法
MySQL 写法
UPDATE t SET status = 'x' WHERE id = 1;
SELECT ROW_COUNT(); -- 默认 changed 口径:值没变就返回 0
-- 想要 found 口径需要连接层带 CLIENT_FOUND_ROWS 标记
-- 各驱动参数名不同,改前先确认当前驱动的默认值
-- 例如 Connector/J 的 useAffectedRows 就决定是否带这个标记
-- 值相同也期望“命中 1 行”的脚本,必须用 found 口径PostgreSQL 写法
PostgreSQL 写法
UPDATE t SET status = 'x' WHERE id = 1;
-- 命令标签直接打印:UPDATE 1,匹配到就算
-- 在函数或存储过程里取行数
GET DIAGNOSTICS n = ROW_COUNT; -- 最近一条语句处理的行数
RAISE NOTICE 'affected=%', n; -- 调试时打印出来两库返回值对照
| 情形 | MySQL changed 口径 | PostgreSQL |
|---|---|---|
| 匹配 1 行且值变化 | 1 | 1 |
| 匹配 1 行但值未变 | 0 | 1 |
| 匹配 0 行 | 0 | 0 |
| 匹配 3 行、其中 1 行值变化 | 1 | 3 |
幂等脚本要区分两种判断:判「记录是否存在」用 found 口径,判「是否真的发生变更」用 changed 口径。把 changed 计 0 直接当成记录不存在,是最常见的误判。
PostgreSQL 的 ROW_COUNT 是「处理过的行数」,UPDATE 值没变同样计数,因此更接近 found 口径,不能当作「数据变了」的证据。