能,但需防null:若col为null,则col + val结果仍为null;应改用coalesce(col, 0) + val或where col is not null,建表时设default 0更稳妥。

UPDATE t SET col = col + val 能直接累加更新吗
能,但必须确保目标列不是 NULL,否则整行会变成 NULL。SQL 中任何数与 NULL 做算术运算结果都是 NULL,这是最常踩的坑。
比如执行 UPDATE orders SET total = total + 100 WHERE id = 123,如果 total 当前是 NULL,那更新后还是 NULL,而不是 100。
- 用
COALESCE(total, 0) + 100替代total + 100,安全兜底 - 或先用
WHERE total IS NOT NULL过滤,但会漏掉初始为NULL的记录 - 建表时尽量设默认值:
total DECIMAL(10,2) DEFAULT 0,从源头避免
MySQL 和 PostgreSQL 对 UPDATE 累加行为一致吗
基本一致,但细节有差异:
-
UPDATE语句本身在两者中都支持SET col = col + val写法,语义相同 - MySQL 允许在同一个语句中多次引用同一列(如
SET a = a + 1, b = a * 2),PostgreSQL 不允许——它按逻辑顺序计算,b取的是旧值a,不是刚更新后的值 - PostgreSQL 若需依赖前一列更新结果,得用
WITH子句或分两步更新 - 两者都支持在
WHERE中用子查询,但 MySQL 8.0+ 才支持对同一张表的子查询更新(否则报错ERROR 1093)
UPDATE 累加时并发写入会丢数据吗
会,除非加锁或改用原子操作。单纯 UPDATE t SET cnt = cnt + 1 不是原子的:读取 → 计算 → 写入,三步之间可能被其他事务打断。
典型现象:两个并发请求同时执行 cnt = cnt + 1,预期从 5 变成 7,结果只变成 6。
- MySQL 下可用
SELECT ... FOR UPDATE显式加行锁(需在事务中) - PostgreSQL 推荐用
UPDATE ... SET cnt = cnt + 1 WHERE id = ? RETURNING cnt,配合应用层重试 - 更稳妥的是用数据库原生原子函数,如 PostgreSQL 的
pg_advisory_lock(),或 MySQL 的GET_LOCK() - 高频计数场景,建议移出主表,用 Redis 或专用计数服务
WHERE 条件没命中时,累加更新会报错还是静默失败
静默失败,影响行为为 0 行。这是正常行为,不是 bug。
但容易误判“更新没生效”,尤其当 WHERE 条件含隐式类型转换或空格问题时(比如 WHERE user_id = '123 ' 匹配不到数值型 123)。
- 执行后立刻查
ROW_COUNT()(MySQL)或GET DIAGNOSTICS(PostgreSQL)确认实际影响行数 - 开发阶段可在
WHERE后加AND col IS NOT NULL显式排除无效路径 - 避免在
WHERE中用函数包裹字段(如WHERE UPPER(name) = 'ABC'),会导致索引失效,查不到也看不出原因
实际业务里,累加更新看着简单,真正要稳,得盯住 NULL、并发、匹配逻辑这三块。特别是从日志或监控里看到“更新了但数值不对”,八成是其中某一个没兜住。










