0

我正在使用可重复读取隔离级别处理事务。我想在此事务中合并 Try-Catch 和错误处理程序功能。当我运行代码时,我收到一条错误消息:Msg 102, Level 15, State 1, Line 18 Incorrect syntax near 'BEGIN'。消息 102,级别 15,状态 1,第 23 行“@errnum”附近的语法不正确。

如何成功完成此交易?或 编写此交易的正确方法是什么?

这是我现在的工作:

CREATE PROCEDURE ItemFlow (@Name  VARCHAR(50),
                                @aPrice  MONEY,
                                @bPrice MONEY)
AS
SET TRANSACTION ISOLATION LEVEL REPEATABLE READ;
GO
  BEGIN TRAN
      IF EXISTS (SELECT 1
                 FROM   Cashier
                 WHERE  Item = '@Item')
        UPDATE Cashier
        SET    bPrice = '@bPrice',
               aprice = '@aprice'
        WHERE  Item = '@Item'
      ELSE
        INSERT INTO Cashier
                    (Item, aPrice, bPrice)
        VALUES      ('@Item', '@aPrice', '@bPrice')
                     END
BEGIN TRY
    EXECUTE ItemFlow
END TRY

BEGIN CATCH
    @errnum = ERROR_NUMBER(),
           @severity = ERROR_SEVERITY(),
           @errstate = ERROR_STATE(),
           @proc = ERROR_PROCEDURE(),
           @line = ERROR_LINE(),
           @message = ERROR_MESSAGE()

END CATCH
4

3 回答 3

1

一个问题是GO终止create procedure statement. 我总是begin/end与存储过程一起使用:

CREATE PROCEDURE ItemFlow (@Name  VARCHAR(50),
                           @aPrice  MONEY,
                           @bPrice MONEY)
AS
BEGIN
    SET TRANSACTION ISOLATION LEVEL REPEATABLE READ;
    BEGIN TRAN
      IF EXISTS (SELECT 1
                 FROM   Cashier
                 WHERE  Item = '@Item')
        UPDATE Cashier
        SET    bPrice = '@bPrice',
               aprice = '@aprice'
        WHERE  Item = '@Item'
      ELSE
        INSERT INTO Cashier
                    (Item, aPrice, bPrice)
        VALUES      ('@Item', '@aPrice', '@bPrice')
    COMMIT TRAN;
END;  -- ItemFlow

然后,在调用存储过程时需要参数,或者为它们定义的默认值:

BEGIN TRY
    EXECUTE ItemFlow @arg1, @arg2, @arg3
END TRY
BEGIN CATCH
    @errnum = ERROR_NUMBER(),
           @severity = ERROR_SEVERITY(),
           @errstate = ERROR_STATE(),
           @proc = ERROR_PROCEDURE(),
           @line = ERROR_LINE(),
           @message = ERROR_MESSAGE()

END CATCH;
于 2015-01-10T17:48:40.543 回答
1

在实施任何建议的更改之前,请回答:1)为什么在 proc 中调用 proc 本身?和 2)为什么将 ERROR_ 函数设置为变量?你要使用它们吗?如果没有,则无需声明变量。

还:

  • 显然,GO 不能成为其中的一部分。它只是 SSMS 的批处理分隔符。

  • 您有一个@Name未使用的输入参数,以及一个@Item未声明的变量。我怀疑它们是同一回事,所以我使用@Item了作为输入参数而不是@Name.

  • 您在三个查询中使用输入参数作为字符串文字,这是没有意义的。您需要从它们周围删除单引号,以便它们可以充当变量。

  • 并且,请不要将 TRY / CATCH 逻辑与事务分开!

假设调用无限循环并没有真正的意图(proc 在没有条件停止的情况下调用自身),您的代码应如下所示:

CREATE PROCEDURE ItemFlow
(
  @Item  VARCHAR(50),
  @aPrice  MONEY,
  @bPrice MONEY
)
AS
SET NOCOUNT ON;

SET TRANSACTION ISOLATION LEVEL REPEATABLE READ;

BEGIN TRY

  BEGIN TRAN

  IF EXISTS (SELECT 1
             FROM   Cashier
             WHERE  Item = @Item)
  BEGIN
        UPDATE Cashier
        SET    bPrice = @bPrice,
               aprice = @aPrice
        WHERE  Item = @Item;
  END;
  ELSE
  BEGIN
        INSERT INTO Cashier
                    (Item, aPrice, bPrice)
        VALUES      (@Item, @aPrice, @bPrice);
  END;

  COMMIT TRAN;

END TRY
BEGIN CATCH

  IF (@@TRANCOUNT > 0)
  BEGIN
    ROLLBACK TRAN;
  END;

  THROW;

END CATCH;

THROW在 SQL Server 2012 中引入。如果您使用的是 2005 - 2008 R2 的任何版本,请将其替换为THROW

DECLARE @ErrMessage NVARCHAR(4000);
SET @ErrMessage = ERROR_MESSAGE();
RAISERROR(@ErrMessage, 16, 1);
RETURN;
于 2015-01-10T18:15:10.100 回答
0

您的代码有几个问题:

BEGIN 附近出错

GO是一个批处理分隔符。它不是有效的 T-SQL,只有 SSMS 才能理解。您实际上是在提交两个查询:

CREATE PROCEDURE ItemFlow (@Name  VARCHAR(50),
                                @aPrice  MONEY,
                                @bPrice MONEY)
AS
SET TRANSACTION ISOLATION LEVEL REPEATABLE READ;

和:

BEGIN TRAN
...

如您所见,存储过程主体是空的。删除GO以摆脱这种情况。

@errnum 附近的错误

您的变量未声明。此外,您必须使用SELECTSET为这些变量赋值:

DECLARE @errnum int,
        @serverity int,
        (etc.)
        
SELECT @errnum = ERROR_NUMBER(),
       @severity = ERROR_SEVERITY(),
       @errstate = ERROR_STATE(),
       @proc = ERROR_PROCEDURE(),
       @line = ERROR_LINE(),
       @message = ERROR_MESSAGE()

最后一件事:

你有一个BEGIN TRAN但没有一个COMMIT TRAN。在存储过程执行结束时,您的事务仍然处于打开状态。

于 2015-01-10T17:59:20.590 回答