MS SQL Server触发器调用存储过程时SELECT返回新值还是旧值?
问题结论
默认配置下的AFTER触发器调用存储过程时,存储过程读取触发表拿到的是更新后的新值,原有逻辑的取值正确性可以得到保证。
底层逻辑说明
- MS SQL 中声明为
FOR INSERT/UPDATE/DELETE的默认AFTER触发器,触发时机是对应DML操作已经完成对目标表的数据修改、约束校验、索引更新全部执行完毕,仅事务尚未提交的阶段。 - 触发器和触发它的DML操作运行在同一个事务上下文里,同事务内的修改对当前会话的所有操作都是可见的,不受事务隔离级别影响。因此触发器内部调用的存储过程,对触发表的SELECT查询会读到本事务刚写入的新值。
特殊场景注意事项
- 如果你使用的是
INSTEAD OF触发器:这类触发器会替代原DML操作执行,如果你没有在触发器内先手动完成对触发表的修改,就直接调用存储过程,那存储过程读到的就是修改前的旧值。只有在调用存储过程前已经完成了表数据写入,才会读到新值。 - 批量操作场景:MS SQL的触发器是语句级触发,单次更新多行时触发器只会执行一次,如果你的存储过程逻辑是默认处理单行数据的,需要额外适配批量场景,避免逻辑出错。
- 递归触发风险:如果被调用的存储过程内部也会对触发表执行写操作,会再次触发触发器导致递归调用,严重时会触发事务回滚,需要确认是否关闭了服务器层面的递归触发器配置,或者存储过程无对触发表的写逻辑。
场景验证方法
你可以通过以下方式快速确认你的场景符合预期:
- 写测试UPDATE语句修改一条数据的明显标识字段,在存储过程中加临时打印逻辑输出该字段的值,确认和你更新的新值一致即可。
- 测试事务回滚场景:在触发器调用存储过程后主动抛出异常触发事务回滚,可观察到存储过程运行时读到的依然是新值,仅事务回滚后最终数据会恢复旧值,不会影响存储过程运行时的取值正确性。
内容的提问来源于stack exchange,提问作者Dryadwoods
相关产品推荐
相关产品推荐

