Warning: file_get_contents(/data/phpspider/zhask/data//catemap/5/sql/80.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
T-SQL事务-此开始/提交实现是否足够?_Sql_Sql Server_Tsql_Transactions_Acid - Fatal编程技术网

T-SQL事务-此开始/提交实现是否足够?

T-SQL事务-此开始/提交实现是否足够?,sql,sql-server,tsql,transactions,acid,Sql,Sql Server,Tsql,Transactions,Acid,我正在创建一个SQL Server批处理文件,以创建新的数据库对象、将数据插入表等。如果其中一个操作失败,那么我不希望提交任何其他操作 以下包装是否足以完成我要做的事情 BEGIN TRANSACTION --script #1 - create Table1 --script #2 - create Sproc1 --script #3 - insert data load into Table1 COMMIT 因此,如果SS在上面定义的事务中嵌套的任何脚本中遇到错误,则不会提交任何SQ

我正在创建一个SQL Server批处理文件,以创建新的数据库对象、将数据插入表等。如果其中一个操作失败,那么我不希望提交任何其他操作

以下包装是否足以完成我要做的事情

BEGIN TRANSACTION

--script #1 - create Table1
--script #2 - create Sproc1
--script #3 - insert data load into Table1

COMMIT
因此,如果SS在上面定义的事务中嵌套的任何脚本中遇到错误,则不会提交任何SQL DDL或数据加载,对吗

我假设这里不需要显式回滚。是否存在需要显式包含回滚语句的场景?

请参阅。某些错误只会终止正在运行的语句,并在下一条语句上继续执行。那太糟糕了

您可以通过将XACT_ABORT设置为ON,确保脚本中没有设置它,并在出现错误时回滚或关闭连接来实现这一点。例如:

SET XACT_ABORT ON
BEGIN TRANSACTION

--script #1 - create Table1
--script #2 - create Sproc1
--script #3 - insert data load into Table1

COMMIT
但正如@Larnu所指出的,最好使用并显式回滚事务


请注意,某些DDL语句必须在自己的批处理中,或者是批处理中的第一条语句。因此,您必须在脚本中使用动态SQL或多个批处理。并尝试..CATCH只能在单个批处理中工作。

显示这一点的最简单方法是使用一些示例代码。首先,让我们进行如下设置:

BEGIN TRANSACTION;

    DECLARE @SQL nvarchar(MAX);

    CREATE TABLE dbo.Table1 (ID int);
    --Needs to be dynamic, as CREATE PROC must be in its own batch
    SET @SQL = N'
CREATE PROC dbo.Proc1 @i int AS

    SELECT ID
    FROM dbo.Table1
    WHERE ID = @i;';
    EXEC sp_executesql @SQL;

    --Works fine
    INSERT INTO dbo.Table1 (ID)
    SELECT 1;
    --Fails
    INSERT INTO dbo.Table1 (ID)
    SELECT 0/0;   

COMMIT;
现在,如果我们尝试以下方法,则会出现错误:

SELECT *
FROM dbo.Table1;
您会注意到这是有效的,并返回数据。以下语句也不会返回任何错误:

EXEC dbo.Proc1 @i = 1;
GO
--Both work
DROP PROC dbo.Proc1;
DROP TABLE dbo.Table1;
其他语句都没有在除法为零的错误上回滚,这不是您想要的。正如我在评论中所说,您需要使用
TRY…CATCH
;因此,您的批次看起来像:

BEGIN TRY
    BEGIN TRANSACTION Migration;

    DECLARE @SQL nvarchar(MAX);

    CREATE TABLE dbo.Table1 (ID int);

    --Needs to be dynamic, as CREATE PROC must be in its own batch
    SET @SQL = N'
CREATE PROC dbo.Proc1 @i int AS

    SELECT ID
    FROM dbo.Table1
    WHERE ID = @i;';
    EXEC sp_executesql @SQL;

    --Works fine
    INSERT INTO dbo.Table1 (ID)
    SELECT 1;
    --Fails
    INSERT INTO dbo.Table1 (ID)
    SELECT 0/0;   

    COMMIT;
END TRY
BEGIN CATCH
    ROLLBACK TRANSACTION Migration;
END CATCH
现在,如果我们尝试上述任何一种说法,它们都将失败:

--Doesn't work
SELECT *
FROM dbo.Table1;
GO
--Doesn't work
EXEC dbo.Proc1 @i = 1;
GO
--Deosn't work
DROP PROC dbo.Proc1;
DROP TABLE dbo.Table1;
GO

正如我在上面的评论中所说,这意味着
SELECT
EXEC
DROP
语句都会失败,因为对象不存在。

您使用的是InnoDb还是MySQL?MySQL将创建表作为一个事务处理。因此,即使您将其放入外部事务包装器中,它也无法撤消。我使用的是SQL Server 2016,您需要使用
开始尝试。。。CATCH
带有显式的
回滚功能。您能在事务中创建存储过程吗?@Larnu-如果在“开始事务”之后但在“提交”之前发生错误,最新版本的sql server不会在后台简单地回滚当前事务吗?这是有关XACT\U ABORT的有趣信息。我认为大多数非sql专家都会假设,当嵌套sql语句中发生错误时,标准的“BeginTransaction/COMMIT”将实现完全回滚。你能想象一下现实世界中有人需要在不启用XACT_ABORT的情况下运行“BEGIN TRANSACTION/COMMIT”吗?我不确定下面的语句是什么意思:“注意,一些DDL语句必须在它们自己的批中,或者是批中的第一个语句。”请详细说明?