您认为在t-sql中编写事务有更好的方法吗?是否有更好的方法可以提高使用此事务的应用程序的可维护性和性能?
-- Description: Insert email Receiver under specified subject
-- =============================================
ALTER PROCEDURE [Contact].[Receiver_stpInsert]
@First_Name nvarchar(30),
@Last_Name nvarchar(30),
@Email varchar(60),
@Subject_Id int
AS
BEGIN
SET NOCOUNT ON;
DECLARE @error_num int;
BEGIN TRANSACTION
INSERT INTO Contact.Receiver(First_Name, Last_Name, Email) VALUES(@First_Name, @Last_Name, @Email);
SET @error_num = @@ERROR;
IF (@error_num <> 0)
BEGIN
ROLLBACK;
RETURN;
END
DECLARE @rec_record_id int;
SET @rec_record_id = (SELECT Record_Id FROM Contact.Receiver WHERE Email = @Email);
SET @error_num = @@ERROR;
IF (@error_num <> 0)
BEGIN
ROLLBACK;
RETURN;
END
INSERT INTO Contact.Receiver_Subject(Receiver_Id, Subject_Id) VALUES(@rec_record_id, @Subject_Id);
SET @error_num = @@ERROR;
IF (@error_num <> 0)
BEGIN
ROLLBACK;
RETURN;
END
SET @error_num = @@ERROR;
IF (@error_num <> 0)
BEGIN
ROLLBACK;
RETURN;
END
ELSE
BEGIN
Commit;
END
END
答案 0 :(得分:35)
如果您使用的是SQL 2005或更高版本,则可以使用TRY...CATCH块,如下所示:
BEGIN TRY
BEGIN TRANSACTION;
INSERT INTO Contact.Receiver(First_Name, Last_Name, Email) VALUES (@First_Name, @Last_Name, @Email);
... other inserts etc
...
COMMIT TRANSACTION;
END TRY
BEGIN CATCH
IF @@TRANCOUNT > 0
ROLLBACK TRANSACTION;
END CATCH;
这样,您不会重复检查@@ ERROR的相同代码块。如果您想知道发生了什么错误,可以在BEGIN CATCH块中获取各种信息:
- ERROR_NUMBER()返回错误编号。
- ERROR_SEVERITY()返回严重性。
- ERROR_STATE()返回错误状态编号。
- ERROR_PROCEDURE()返回存储过程或触发器的名称 发生错误的地方。
- ERROR_LINE()返回导致该例程的例程内的行号 错误。
- ERROR_MESSAGE()返回错误消息的完整文本。文本 包括为任何提供的值 可替代的参数,例如 长度,对象名称或时间。
答案 1 :(得分:12)
很长一段时间以来,我一直在倡导使用TRY/CATCH and nested transactions in stored procedures。
与@@ ERROR检查相比,此模式不仅为您提供了TRY / CATCH块的简化错误处理,而且还为过程调用提供了全有或全无的嵌套语义。
如果在事务的上下文中调用该过程,则该过程仅回滚其自己的更改,并让调用者决定是回滚嵌入事务还是尝试备用错误路径。
create procedure [usp_my_procedure_name]
as
begin
set nocount on;
declare @trancount int;
set @trancount = @@trancount;
begin try
if @trancount = 0
begin transaction
else
save transaction usp_my_procedure_name;
-- Do the actual work here
lbexit:
if @trancount = 0
commit;
end try
begin catch
declare @error int, @message varchar(4000), @xstate int;
select @error = ERROR_NUMBER(), @message = ERROR_MESSAGE(), @xstate = XACT_STATE();
if @xstate = -1
rollback;
if @xstate = 1 and @trancount = 0
rollback
if @xstate = 1 and @trancount > 0
rollback transaction usp_my_procedure_name;
raiserror ('usp_my_procedure_name: %d: %s', 16, 1, @error, @message) ;
return;
end catch
end
这种方法的缺点是:
还要谨慎使用SET XACT_ABORT ON。此设置将导致批处理在任何错误时中止事务。这引起任何TRY / CATCH交易处理基本无用,我建议避免使用。
答案 2 :(得分:7)
如果你有SQL Server 2000或之前,那么是 - 检查@@ERROR
值基本上就是你所能做的。
使用SQL Server 2005,Microsoft引入了TRY ... CATCH结构,使其更容易:
BEGIN TRY
......
-- your T-SQL code here
......
END TRY
BEGIN CATCH
SELECT
ERROR_NUMBER() AS ErrorNumber,
ERROR_SEVERITY() AS ErrorSeverity,
ERROR_STATE() AS ErrorState,
ERROR_PROCEDURE() AS ErrorProcedure,
ERROR_LINE() AS ErrorLine,
ERROR_MESSAGE() AS ErrorMessage
-- do other steps, if you want
END CATCH
答案 3 :(得分:4)
不久前问道。 My answer带有TRY / CATCH模板
答案 4 :(得分:2)
如果您使用的是sql 2005或更高版本,则应考虑使用TRY CATCH方法
答案 5 :(得分:2)
您可以将它全部包装在try catch中,然后您只需要在一个位置编写回滚代码。有关详细信息,请参阅this。