显式事务必须用BEGIN TRANSACTION显式开启并由COMMIT/ROLLBACK显式结束,支持SAVEPOINT等精细控制;而隐式事务依赖SET IMPLICIT_TRANSACTIONS ON自动启停、不支持保存点,且DDL会隐式提交,易导致事务边界模糊和不可回滚风险。
因为显式事务能让你完全掌控语句的提交边界,避免隐式提交或自动提交模式下意外的数据残留、部分生效或不可回滚状态。
当 SET AUTOCOMMIT ON 时,每条 INSERT、UPDATE、DELETE 都是独立事务:执行完立刻落盘,无法回滚。哪怕你只差最后一步校验就出错,前面的修改已不可逆。
而显式事务强制你写 BEGIN TRANSACTION → 执行多条语句 → 最后决定 COMMIT 或 ROLLBACK。整个过程像“暂存区”,DBA 可以在提交前做数据一致性检查、日志比对、甚至人工确认。
autocommit on 适合单条 DML 的脚本化操作,但不适合业务逻辑组合(比如先删旧记录、再插新记录、再更新关联表)autocommit off + 显式 BEGIN TRANSACTION 是唯一能保证多步操作原子性的手段CREATE TABLE)本身会触发隐式提交,哪怕在显式事务内也会提前结束当前事务 —— 这点容易被忽略SET IMPLICIT_TRANSACTIONS ON 不等于显式事务SET IMPLICIT_TRANSACTIONS ON 确实会在每个 DML 前自动开事务,但它不改变事务起点的可见性:你无法用 SAVE TRANSACTION 设保存点,也无法在事务中途做条件判断后再决定是否继续;它只是把“没写 BEGIN”变成“系统帮你补一个”,但控制权仍在语句级。
SELECT 不启动事务,但第一个 INSERT 就会触发事务开启,后续所有 DML 都绑定到该事务,直到你显式 COMMIT 或 ROLLBACK
SAVE TRANSACTION)的流程,必须用 BEGIN TRANSACTION
资深 DBA 写 BEGIN TRANSACTION 后,一定会顺手检查这三项,否则可能引发阻塞、死锁或静默失败:
@@TRANCOUNT 是否为 1 —— 如果之前已有未关闭事务,BEGIN 只会让计数器加 1,COMMIT 也只会减 1,最终导致事务“悬空”SELECT(尤其是带大结果集或未加 NOLOCK 的查询),它会延长锁持有时间,拖慢并发GO 分隔事务语句 —— GO 是 SSMS/SQLCMD 的批处理分隔符,不是 T-SQL 语句,它会中断事务上下文,导致 COMMIT 失效事务不是加个 BEGIN 和 COMMIT 就万事大吉;关键在于你是否清楚每一行语句在哪个事务上下文中运行、锁何时获取又何时释放、以及出错时回滚的边界是否真能覆盖全部副作用。这才是老手和新手最硬的一道分水岭。