Cha*_*e K 13 sql-server stored-procedures t-sql transaction sql-server-2012
我需要在单个事务中执行 UPDATE 和 INSERT。该代码本身运行良好,但我希望能够轻松调用它并传入所需的参数。当我尝试将这个事务嵌套在一个存储过程中时,我遇到了很多语法错误。
如何封装以下代码以便轻松调用?
BEGIN TRANSACTION AssignUserToTicket
GO
DECLARE @updateAuthor varchar(100)
DECLARE @assignedUser varchar(100)
DECLARE @ticketID bigint
SET @updateAuthor = 'user1'
SET @assignedUser = 'user2'
SET @ticketID = 123456
UPDATE tblTicket SET ticketAssignedUserSamAccountName = @assignedUser WHERE (ticketID = @ticketID);
INSERT INTO [dbo].[tblTicketUpdate]
([ticketID]
,[updateDetail]
,[updateDateTime]
,[userSamAccountName]
,[activity])
VALUES
(@ticketID,
'Assigned ticket to ' + @assignedUser,
GetDate(),
@updateAuthor,
'Assign');
GO
COMMIT TRANSACTION AssignUserToTicket
Run Code Online (Sandbox Code Playgroud)
Han*_*non 21
您需要用CREATE PROCEDURE ...语法包装该代码,并删除GO之后BEGIN TRANSACTION和之前的语句COMMIT TRANSACTION。
GO
CREATE PROCEDURE dbo.AssignUserToTicket
(
@updateAuthor varchar(100)
, @assignedUser varchar(100)
, @ticketID bigint
)
AS
BEGIN
BEGIN TRANSACTION;
SAVE TRANSACTION MySavePoint;
SET @updateAuthor = 'user1';
SET @assignedUser = 'user2';
SET @ticketID = 123456;
BEGIN TRY
UPDATE dbo.tblTicket
SET ticketAssignedUserSamAccountName = @assignedUser
WHERE (ticketID = @ticketID);
INSERT INTO [dbo].[tblTicketUpdate]
(
[ticketID]
,[updateDetail]
,[updateDateTime]
,[userSamAccountName]
,[activity]
)
VALUES (
@ticketID
, 'Assigned ticket to ' + @assignedUser
, GetDate()
, @updateAuthor
, 'Assign'
);
COMMIT TRANSACTION
END TRY
BEGIN CATCH
IF @@TRANCOUNT > 0
BEGIN
ROLLBACK TRANSACTION MySavePoint; -- rollback to MySavePoint
END
END CATCH
END;
GO
Run Code Online (Sandbox Code Playgroud)
另请注意,我添加了一个TRY...CATCH语句块以允许ROLLBACK TRANSACTION在发生某些错误时执行语句。您可能需要比这更好的错误处理,但如果不了解您的要求,那充其量是困难的。
一些不错的阅读:
如果您想正确处理可以处理事务的嵌套存储过程(无论是从 T-SQL 还是应用程序代码开始),那么您应该遵循我在以下答案中描述的模板:
您会注意到与您在此处尝试的内容有两个不同之处:
RAISERROR在CATCH块内使用。这会将错误冒泡到调用级别(无论是在 DB 还是应用程序层),因此可以就发生错误的事实做出决定。
没有SAVE TRANSACTION。我从来没有找到使用它的案例。我知道有些人更喜欢它,但是在我在我工作过的任何地方做过的所有事情中,任何嵌套级别中发生错误的概念意味着已经完成的任何工作都是无效的。通过使用,SAVE TRANSACTION您只会恢复到调用此存储过程之前的状态,而使现有过程保持有效。
如果您想了解有关 的更多详细信息SAVE TRANSACTION,请查看此答案中的信息:
另一个问题SAVE TRANSACTION是其行为的细微差别,如SAVE TRANSACTION的 MSDN 页面中所述(强调已添加):
事务中允许使用重复的保存点名称,但指定保存点名称的 ROLLBACK TRANSACTION 语句只会将事务回滚到使用该名称的最近的SAVE TRANSACTION。
这意味着,您需要非常小心地为每个存储过程中的每个保存点指定一个名称,该名称在所有存储过程中的所有保存点中都是唯一的。下面的例子说明了这一点。
第一个示例显示了重用保存点名称时会发生什么;仅回滚最低级别的保存点。
IF (OBJECT_ID(N'tempdb..#SaveTranTestA') IS NOT NULL)
BEGIN
DROP TABLE #SaveTranTestA;
END;
CREATE TABLE #SaveTranTestA (SomeVal INT NOT NULL);
BEGIN TRAN; -- start level 1
SAVE TRANSACTION MySavePoint;
SELECT @@TRANCOUNT AS [TranCount]; -- 1
INSERT INTO #SaveTranTestA (SomeVal) VALUES (100);
BEGIN TRAN; -- start level 2
SAVE TRANSACTION MySavePoint;
SELECT @@TRANCOUNT AS [TranCount]; -- 2
INSERT INTO #SaveTranTestA (SomeVal) VALUES (200);
COMMIT; -- exit level 2
SELECT @@TRANCOUNT AS [TranCount]; -- 1
SELECT * FROM #SaveTranTestA;
-- 100
-- 200
ROLLBACK TRANSACTION MySavePoint; -- error occurred; undo actions up to this point
SELECT @@TRANCOUNT AS [TranCount]; -- 1
SELECT * FROM #SaveTranTestA;
-- 100
COMMIT; -- exit level 1
SELECT @@TRANCOUNT AS [TranCount]; -- 0
SELECT * FROM #SaveTranTestA;
-- 100
Run Code Online (Sandbox Code Playgroud)
第二个例子展示了当你使用唯一的保存点名称时会发生什么;所需级别的保存点被回滚。
IF (OBJECT_ID(N'tempdb..#SaveTranTestB') IS NOT NULL)
BEGIN
DROP TABLE #SaveTranTestB;
END;
CREATE TABLE #SaveTranTestB (SomeVal INT NOT NULL);
BEGIN TRAN; -- start level 1
SAVE TRANSACTION MySavePointUno;
SELECT @@TRANCOUNT AS [TranCount]; -- 1
INSERT INTO #SaveTranTestB (SomeVal) VALUES (100);
BEGIN TRAN; -- start level 2
SAVE TRANSACTION MySavePointDos;
SELECT @@TRANCOUNT AS [TranCount]; -- 2
INSERT INTO #SaveTranTestB (SomeVal) VALUES (200);
COMMIT; -- exit level 2
SELECT @@TRANCOUNT AS [TranCount]; -- 1
SELECT * FROM #SaveTranTestB;
-- 100
-- 200
ROLLBACK TRANSACTION MySavePointUno; --error occurred; undo actions up to this point
SELECT @@TRANCOUNT AS [TranCount]; -- 1
SELECT * FROM #SaveTranTestB;
-- <no rows>
COMMIT; -- exit level 1
SELECT @@TRANCOUNT AS [TranCount]; -- 0
SELECT * FROM #SaveTranTestB;
-- <no rows>
Run Code Online (Sandbox Code Playgroud)| 归档时间: |
|
| 查看次数: |
92214 次 |
| 最近记录: |