在回滚的事务中仍会发生哪些事件?

J.D*_*.D. 7 sql-server dml transaction ddl sql-server-2016

当它们所属的事务被回滚时,所有​​数据修改都被撤消是真的吗?

例如,如果一个游标只执行了 100 次在每次迭代中更新表的存储过程,所有这些更新都会回滚吗?

DDL 语句会回滚吗?...例如 DROP TABLE 或 CREATE VIEW?DROP DATABASE 呢?

我知道某些语句仍然执行,尽管像 PRINT“MESSAGE”。

我只是想了解仍然会发生哪些类型的事件。

Sol*_*zky 8

对于允许在显式事务中执行的语句(即BEGIN TRAN,或天堂禁止IMPLICIT_TRANSACTIONSON),我只知道以下两个不受 a 影响ROLLBACK(尽管从技术上讲,两者在某种意义上都有些“作弊”):

  1. 针对表变量的 DML 语句(变量,甚至表变量,不参与事务)

  2. 通过链接服务器执行的语句,并且OPENQUERY(即使使用环回服务器定义连接到当前实例)如果您禁用了“远程 proc 事务提升”的链接服务器属性(这样它就不会尝试加入当前交易)。

    OPENQUERY(禁用该选项)之所以有效,是因为它建立了单独的连接。还有其他类似的方法可以在 T-SQL 中建立单独的连接。David Browne 在评论中提到了扩展存储过程。我们还可以将 SQLCLR 方法(无论它们公开为什么 T-SQL 对象类型)添加到该列表中,但前提是建立常规/外部连接,enlist=false;在连接字符串中指定“ ”。我们可能还可以添加 OLE 自动化存储过程(即sp_OA*),但我不是 100% 确定这些。

  3. 可能是可以明确的事务中执行,但不能被回滚一个或两个语句,我也许以前遇到了很多年了,但我不记得它是什么,可能是用户错误(一些其他用户,当然;-),因此您必须尽可能多地查阅文档以了解每个语句/操作和/或测试的细节(有时文档不正确......它会发生)。

  4. 不确定这是否重要,因为它不是一个明确的变化,但也不能回到交易开始之前的状态(因为它甚至没有意义):Tibor Karaszi 在一篇文章中指出评论“使用身份/序列值”可能符合条件。我已经测试并确认序列不会返回请求的值。

    类似地,另一个不受回滚影响的数据库状态值,而不是用户数据,是当前/上次使用的时间戳值(这是每个数据库,由系统变量返回@@DBTS;也通过测试确认)

  5. 不确定这些是否计数,因为它们既不是显式更改,也不是数据库状态,但它们的值不受回滚的影响:在评论中,David Browne 提到SESSION_CONTEXT,这是每个会话的属性。沿着同样的思路,我们可以包括相关的/相似的CONTEXT_INFO

如果一个游标只执行了 100 次在每次迭代中更新表的存储过程,所有这些更新都会回滚吗?

是的,这就是显式事务的目的:将语句组合成一个原子工作单元。

DDL 语句会回滚吗?...例如 DROP TABLE 或 CREATE VIEW?DROP DATABASE 呢?

一些(也许大多数)是的。有些没有。你可能应该测试一下。例如,这里有一些执行回滚的 DDL:

USE [tempdb];

IF (OBJECT_ID(N'dbo.DropMe') IS NOT NULL)
BEGIN
  DROP TABLE dbo.DropMe;
END;

CREATE TABLE dbo.DropMe (col1 INT);

BEGIN TRAN;

DROP TABLE dbo.DropMe;

ROLLBACK TRAN;

SELECT * FROM dbo.[DropMe];
Run Code Online (Sandbox Code Playgroud)

但是,相反,这里有一些无法在显式(或隐式)事务中执行的 DDL:

CREATE DATABASE [DropMe];
BEGIN TRAN;
DROP DATABASE [DropMe];
/*
Msg 574, Level 16, State 0, Line XXXXX
DROP DATABASE statement cannot be used inside a user transaction.
*/
ROLLBACK;
Run Code Online (Sandbox Code Playgroud)

因此,只需将上面的两个示例重新编写为您好奇或需要明确答案的其他陈述。