Warning: file_get_contents(/data/phpspider/zhask/data//catemap/5/sql/84.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

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/7/sql-server/23.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
SQL Server 2012:提交与存储过程内部的begin tran不匹配_Sql_Sql Server_Stored Procedures_Transactions - Fatal编程技术网

SQL Server 2012:提交与存储过程内部的begin tran不匹配

SQL Server 2012:提交与存储过程内部的begin tran不匹配,sql,sql-server,stored-procedures,transactions,Sql,Sql Server,Stored Procedures,Transactions,我在SQL Server 2012 Express中编写了此存储过程 ALTER PROCEDURE [Dictionaries].[InsertCountry] (@p_countryName nvarchar(128) , @ret_countryId int OUTPUT) AS BEGIN DECLARE @TransactionName VARCHAR(20) = 'INST_COUNTRY'; BEGIN TRANSACTION @TransactionName;

我在SQL Server 2012 Express中编写了此存储过程

ALTER PROCEDURE [Dictionaries].[InsertCountry]
(@p_countryName nvarchar(128)
 , @ret_countryId int OUTPUT)
AS
BEGIN
    DECLARE @TransactionName VARCHAR(20) = 'INST_COUNTRY';

    BEGIN TRANSACTION @TransactionName;

IF len(@p_countryName) <= 3
BEGIN
        SET @ret_countryId = null
        ROLLBACK TRANSACTION @TransactionName;
END

INSERT INTO [Dictionaries].[CountryDetails] (name)
VALUES (@p_countryName);    

SET @ret_countryId = @@IDENTITY

INSERT INTO [Dictionaries].[Places] (name, Discriminator , CountryDetails_Id, RegionDetails_Id, CityDetails_Id)
VALUES (@p_countryName, 'Country' , @ret_countryId, null, null);

COMMIT TRANSACTION @TransactionName;
END

这段代码有什么问题?

首先回滚,然后提交。这是一个错误。您可能打算在回滚后返回。

首先回滚,然后提交。这是一个错误。您可能打算在回滚后返回。

您可以使用Microsoft提供的一个存储过程模板/样板文件:示例B或C;对于非嵌套事务或嵌套事务。此外,如果某些条件不满足,可以使用RAISERROR生成异常

基于上一个模板的示例-[嵌套事务]:

IF EXISTS (SELECT name FROM sys.objects
           WHERE name = N'dbo.Country_Insert')
    DROP PROCEDURE dbo.Country_Insert;
GO
CREATE PROCEDURE dbo.Country_Insert
(
    @p_countryName nvarchar(128)
    ,@ret_countryId int OUTPUT
)
AS
    -- Detect whether the procedure was called
    -- from an active transaction and save
    -- that for later use.
    -- In the procedure, @TranCounter = 0
    -- means there was no active transaction
    -- and the procedure started one.
    -- @TranCounter > 0 means an active
    -- transaction was started before the 
    -- procedure was called.
    DECLARE @TranCounter INT;
    SET @TranCounter = @@TRANCOUNT;
    IF @TranCounter > 0
        -- Procedure called when there is
        -- an active transaction.
        -- Create a savepoint to be able
        -- to roll back only the work done
        -- in the procedure if there is an
        -- error.
        SAVE TRANSACTION ProcedureSave;
    ELSE
        -- Procedure must start its own
        -- transaction.
        BEGIN TRANSACTION;
    -- Modify database.
    BEGIN TRY

    -- Custom source code
IF len(@p_countryName) <= 3
BEGIN
        SET @ret_countryId = null
        RAISERROR('Wrong contry name', 16, 1);
END

INSERT INTO [Dictionaries].[CountryDetails] (name)
VALUES (@p_countryName);    

SET @ret_countryId = SCOPE_IDENTITY() -- @@IDENTITY isn't safe

INSERT INTO [Dictionaries].[Places] (name, Discriminator , CountryDetails_Id, RegionDetails_Id, CityDetails_Id)
VALUES (@p_countryName, 'Country' , @ret_countryId, null, null);
    -- End of Custom source code

        -- Get here if no errors; must commit
        -- any transaction started in the
        -- procedure, but not commit a transaction
        -- started before the transaction was called.
        IF @TranCounter = 0
            -- @TranCounter = 0 means no transaction was
            -- started before the procedure was called.
            -- The procedure must commit the transaction
            -- it started.
            COMMIT TRANSACTION;
    END TRY
    BEGIN CATCH
        -- An error occurred; must determine
        -- which type of rollback will roll
        -- back only the work done in the
        -- procedure.
        IF @TranCounter = 0
            -- Transaction started in procedure.
            -- Roll back complete transaction.
            ROLLBACK TRANSACTION;
        ELSE
            -- Transaction started before procedure
            -- called, do not roll back modifications
            -- made before the procedure was called.
            IF XACT_STATE() <> -1
                -- If the transaction is still valid, just
                -- roll back to the savepoint set at the
                -- start of the stored procedure.
                ROLLBACK TRANSACTION ProcedureSave;
                -- If the transaction is uncommitable, a
                -- rollback to the savepoint is not allowed
                -- because the savepoint rollback writes to
                -- the log. Just return to the caller, which
                -- should roll back the outer transaction.

        -- After the appropriate rollback, echo error
        -- information to the caller.
        DECLARE @ErrorMessage NVARCHAR(4000);
        DECLARE @ErrorSeverity INT;
        DECLARE @ErrorState INT;

        SELECT @ErrorMessage = ERROR_MESSAGE();
        SELECT @ErrorSeverity = ERROR_SEVERITY();
        SELECT @ErrorState = ERROR_STATE();

        RAISERROR (@ErrorMessage, -- Message text.
                   @ErrorSeverity, -- Severity.
                   @ErrorState -- State.
                   );
    END CATCH
GO

注意:如您所见,我使用了范围\标识而不是@标识。原因已解释。

您可以使用Microsoft提供的一个存储过程模板/样板:示例B或C;对于非嵌套事务或嵌套事务。此外,如果某些条件不满足,可以使用RAISERROR生成异常

基于上一个模板的示例-[嵌套事务]:

IF EXISTS (SELECT name FROM sys.objects
           WHERE name = N'dbo.Country_Insert')
    DROP PROCEDURE dbo.Country_Insert;
GO
CREATE PROCEDURE dbo.Country_Insert
(
    @p_countryName nvarchar(128)
    ,@ret_countryId int OUTPUT
)
AS
    -- Detect whether the procedure was called
    -- from an active transaction and save
    -- that for later use.
    -- In the procedure, @TranCounter = 0
    -- means there was no active transaction
    -- and the procedure started one.
    -- @TranCounter > 0 means an active
    -- transaction was started before the 
    -- procedure was called.
    DECLARE @TranCounter INT;
    SET @TranCounter = @@TRANCOUNT;
    IF @TranCounter > 0
        -- Procedure called when there is
        -- an active transaction.
        -- Create a savepoint to be able
        -- to roll back only the work done
        -- in the procedure if there is an
        -- error.
        SAVE TRANSACTION ProcedureSave;
    ELSE
        -- Procedure must start its own
        -- transaction.
        BEGIN TRANSACTION;
    -- Modify database.
    BEGIN TRY

    -- Custom source code
IF len(@p_countryName) <= 3
BEGIN
        SET @ret_countryId = null
        RAISERROR('Wrong contry name', 16, 1);
END

INSERT INTO [Dictionaries].[CountryDetails] (name)
VALUES (@p_countryName);    

SET @ret_countryId = SCOPE_IDENTITY() -- @@IDENTITY isn't safe

INSERT INTO [Dictionaries].[Places] (name, Discriminator , CountryDetails_Id, RegionDetails_Id, CityDetails_Id)
VALUES (@p_countryName, 'Country' , @ret_countryId, null, null);
    -- End of Custom source code

        -- Get here if no errors; must commit
        -- any transaction started in the
        -- procedure, but not commit a transaction
        -- started before the transaction was called.
        IF @TranCounter = 0
            -- @TranCounter = 0 means no transaction was
            -- started before the procedure was called.
            -- The procedure must commit the transaction
            -- it started.
            COMMIT TRANSACTION;
    END TRY
    BEGIN CATCH
        -- An error occurred; must determine
        -- which type of rollback will roll
        -- back only the work done in the
        -- procedure.
        IF @TranCounter = 0
            -- Transaction started in procedure.
            -- Roll back complete transaction.
            ROLLBACK TRANSACTION;
        ELSE
            -- Transaction started before procedure
            -- called, do not roll back modifications
            -- made before the procedure was called.
            IF XACT_STATE() <> -1
                -- If the transaction is still valid, just
                -- roll back to the savepoint set at the
                -- start of the stored procedure.
                ROLLBACK TRANSACTION ProcedureSave;
                -- If the transaction is uncommitable, a
                -- rollback to the savepoint is not allowed
                -- because the savepoint rollback writes to
                -- the log. Just return to the caller, which
                -- should roll back the outer transaction.

        -- After the appropriate rollback, echo error
        -- information to the caller.
        DECLARE @ErrorMessage NVARCHAR(4000);
        DECLARE @ErrorSeverity INT;
        DECLARE @ErrorState INT;

        SELECT @ErrorMessage = ERROR_MESSAGE();
        SELECT @ErrorSeverity = ERROR_SEVERITY();
        SELECT @ErrorState = ERROR_STATE();

        RAISERROR (@ErrorMessage, -- Message text.
                   @ErrorSeverity, -- Severity.
                   @ErrorState -- State.
                   );
    END CATCH
GO

注意:如您所见,我使用了范围\标识而不是@标识。原因已解释。

回滚后,我想退出存储过程。回滚后只需添加RETURN关键字?是的,只需使用正常的控制流即可。确保不执行提交。按您喜欢的方式执行。回滚后,我想从存储过程中退出。回滚后只需添加RETURN关键字?是的,只需使用正常的控制流即可。确保不执行提交。随便你怎么做。