事务处理核心是保证数据一致性,需明确边界、合理设隔离级、避免长事务并确保可靠回滚;单业务操作应原子执行,批量操作分批提交,优先用upsert防并发冲突,异常必须全覆盖回滚。

事务处理的核心是保证数据一致性,插入和更新操作尤其需要谨慎设计。关键在于明确事务边界、合理控制隔离级别、避免长事务,并确保错误时能可靠回滚。
明确事务范围,避免隐式提交
不要依赖数据库默认的自动提交模式处理业务逻辑。显式使用 BEGIN TRANSACTION(或 START TRANSACTION)开始,用 COMMIT 或 ROLLBACK 明确结束。尤其在循环插入或批量更新中,切忌把整个大循环包在一个事务里——容易锁表、占内存、超时失败。
- 单条业务操作(如“下单”)对应一个事务:包含插入订单、扣减库存、记录日志等多步,要么全成,要么全退
- 批量导入场景可分批次提交,例如每 1000 行提交一次,用保存点(SAVEPOINT)细化回滚粒度
- 应用层调用存储过程时,确保过程内部不意外触发 COMMIT(如 PostgreSQL 的 AUTOCOMMIT 模式下某些语句会隐式提交)
优先使用 UPSERT 而非先查后插/更
“先 SELECT 判断是否存在,再 INSERT 或 UPDATE”看似直观,但在并发环境下极易引发重复插入或丢失更新(race condition)。应直接采用数据库原生的 upsert 机制:
- PostgreSQL:用 INSERT ... ON CONFLICT DO UPDATE
- MySQL 8.0+:用 INSERT ... ON DUPLICATE KEY UPDATE
- SQL Server:用 MERGE 语句(注意其执行计划复杂性,小批量推荐用 IF EXISTS ... UPDATE ELSE INSERT 配合 HOLDLOCK 提示)
- 避免在应用层做存在性判断——网络延迟 + 并发 = 不一致风险
合理设置隔离级别,兼顾正确性与性能
读已提交(READ COMMITTED)是大多数 OLTP 场景的起点。仅在必要时升级:
- 防幻读且业务强一致(如财务对账)→ 可选可重复读(REPEATABLE READ),但注意 MySQL 的 RR 级别仍可能幻读(需配合间隙锁)
- 绝对避免在高并发写场景用串行化(SERIALIZABLE)——性能损耗大,死锁概率高
- 读多写少的统计类更新,可考虑用 SELECT ... FOR UPDATE 显式加行锁,但务必确保 WHERE 条件命中索引,否则升为表锁
异常处理必须覆盖所有分支,回滚不可省略
事务中任何一步出错(约束冲突、超时、连接中断),都必须触发回滚。常见疏漏:
- 存储过程中未定义 EXCEPTION 块(PostgreSQL)或 TRY...CATCH(SQL Server),导致错误后继续执行后续语句
- 应用代码里只捕获 SQLState 而忽略具体错误码,把唯一键冲突当成普通错误吞掉,实际应区分处理(如重试、提示用户改名)
- 事务内调用外部服务(如发消息、调 API)失败时,不能仅靠数据库回滚——需实现本地消息表 + 补偿事务,或用 Saga 模式
不复杂但容易忽略:每次写事务前,先问自己三个问题——这个事务是否最小够用?有没有没释放的锁?出错路径是否真能回滚?答案清晰,数据才稳。










