我正在使用可重复读取隔离级别处理事务。 我想在此事务中包含Try-Catch和错误处理程序功能。 当我运行代码时,我收到一条错误消息: Msg 102,Level 15,State 1,Line 18 'BEGIN'附近的语法不正确。 Msg 102,Level 15,State 1,Line 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
答案 0 :(得分:1)
一个问题是终止GO
的{{1}}。我总是使用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
答案 1 :(得分:0)
您的代码存在一些问题:
GO
是批处理分隔符。它不是有效的T-SQL,只有SSMS才能理解。您实际上是在提交两个查询:
CREATE PROCEDURE ItemFlow (@Name VARCHAR(50),
@aPrice MONEY,
@bPrice MONEY)
AS
SET TRANSACTION ISOLATION LEVEL REPEATABLE READ;
和
BEGIN TRAN
...
如您所见,存储过程主体为空。删除GO
以摆脱此问题。
您的变量未声明。此外,您必须使用SELECT
或SET
为这些变量分配值:
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
。您的交易在执行结束时仍处于打开状态。
答案 2 :(得分:0)
在实施任何建议的更改之前,请回答:1)为什么要在proc中调用proc本身? 2)为什么要将ERROR_函数设置为变量?你打算用它们吗?如果没有,则无需声明变量。
此外:
显然,GO不能成为其中的一部分。它只是SSMS的批处理分隔符。
您有一个未使用的名为@Name
的输入参数,以及一个未声明的名为@Item
的变量。我怀疑它们是相同的,所以我使用@Item
作为输入参数而不是@Name
。
在三个查询中使用输入参数作为字符串文字,这没有任何意义。您需要从它们周围删除单引号,以便它们可以充当变量。
并且,请 NOT 将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;
SQL Server 2012中引入了 THROW
。如果您使用的是2005 - 2008 R2中的任何内容,请将THROW
替换为:
DECLARE @ErrMessage NVARCHAR(4000);
SET @ErrMessage = ERROR_MESSAGE();
RAISERROR(@ErrMessage, 16, 1);
RETURN;