UPDATE必须在BEGIN TRANSACTION后执行,否则无法回滚;正确流程为BEGIN→UPDATE→校验ROW_COUNT()后COMMIT或ROLLBACK;WHERE须基于主键或唯一索引,避免全表扫描与锁表。

UPDATE必须在BEGIN TRANSACTION之后执行
裸跑UPDATE没有回滚路径,事务是安全底线。MySQL、PostgreSQL、SQL Server都要求显式开启事务才能用ROLLBACK撤回错误操作。
常见错误现象:直接写UPDATE users SET status = 'archived' WHERE id = 105;,执行后发现条件写错、字段名拼错或影响了多行,已无法撤销。
- 正确做法永远是三步:先
BEGIN TRANSACTION→ 再UPDATE→ 最后根据校验结果决定COMMIT或ROLLBACK - MySQL中可省略
BEGIN改用START TRANSACTION;PostgreSQL支持BEGIN或BEGIN WORK;SQL Server必须用BEGIN TRAN - 某些ORM(如Django ORM)默认不自动开事务,需手动包裹
transaction.atomic(),否则save()调用仍是自动提交
UPDATE后必须检查ROW_COUNT()或影响行数
事务只保证原子性,不保证业务逻辑正确。成功执行≠改对了——可能WHERE条件没命中、匹配了0行,也可能意外匹配了100行。
使用场景:修改用户邮箱、调整订单状态、同步账户余额等关键字段时,预期影响行数必须明确(通常是1)。
- MySQL用
SELECT ROW_COUNT();查上一条UPDATE影响的行数;返回0说明没找到目标记录,>1说明条件不唯一 - PostgreSQL用
GET DIAGNOSTICS integer_var = ROW_COUNT;或客户端驱动自动提供result.rowcount - SQL Server用
SELECT @@ROWCOUNT;,注意它会被下一条语句覆盖,必须紧跟UPDATE后执行 - 生产脚本中建议把实际行数写入日志,例如:
INSERT INTO audit_log (op, table_name, affected_rows) VALUES ('UPDATE', 'users', ROW_COUNT());
WHERE条件必须基于主键或唯一索引字段
事务能回滚,但锁表时间、并发冲突、索引失效带来的性能抖动无法靠事务缓解。WHERE不走索引,UPDATE会全表扫描+全表加锁,极易阻塞其他查询。
参数差异:sql_safe_updates=1在MySQL中会拦截无索引WHERE,报错ERROR 1175;但PostgreSQL无此机制,全靠人工审查。
- 安全写法:用
id = 123、order_no = 'ORD-2026-789'(字段有UNIQUE约束) - 危险写法:用
name = 'Alice'(可能重复)、created_at (无索引时全表扫) - 模糊条件如
LIKE '%abc%'或UPPER(email) = 'TEST@EX.COM'会让索引失效,即使加了索引也退化为全表扫描 - 批量更新超过1万行时,应拆成
LIMIT 1000循环(MySQL支持),PostgreSQL需用WITH t AS (SELECT id FROM orders WHERE ... LIMIT 1000) UPDATE ... WHERE id IN (SELECT id FROM t)
先SELECT验证再UPDATE不是可选步骤
事务里执行UPDATE前跳过SELECT,等于把验证责任甩给回滚——而回滚成本远高于预防。SELECT验证是成本最低的纠错环节。
容易踩的坑:以为“反正有事务,错了就回滚”,却忽略了锁等待、长事务阻塞、主从延迟放大等问题。
- 单行更新:先跑
SELECT id, email, updated_at FROM users WHERE id = 105;,确认存在且数据符合预期 - 批量更新:先
SELECT COUNT(*) FROM logs WHERE level = 'ERROR' AND created_at ,再查几条样例<code>SELECT * FROM logs WHERE ... LIMIT 3; - PostgreSQL可用
RETURNING *替代SELECT验证,一次完成“查+改”,但MySQL不支持,需额外语句 - 开发环境务必开启
sql_safe_updates=1,强制要求WHERE带索引字段或加LIMIT,避免习惯性裸跑
事务本身不能代替条件审查,真正容易被忽略的是:WHERE是否真的只命中你要的那一行——这得靠SELECT看,靠索引保,靠日志记,而不是靠COMMIT那一刻的侥幸。

















