我正在编写一个脚本来删除多个表中的记录,但在删除之前,它必须返回一个计数供用户在提交之前进行确认。
这是该剧本的摘要。
BEGIN TRANSACTION SCHEDULEDELETE
BEGIN TRY
DELETE -- delete commands full SQL cut out
DELETE -- delete commands full SQL cut out
DELETE -- delete commands full SQL cut out
PRINT 'X rows deleted. Please commit or rollback.' --calculation cut out.
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
ROLLBACK TRANSACTION SCHEDULEDELETE
PRINT 'Error detected, all changes reversed.'
END CATCH
--COMMIT TRANSACTION SCHEDULEDELETE --Run this if count correct.
--ROLLBACK TRANSACTION SCHEDULEDELETE --Run this if there is any doubt whatsoever.
这是我第一次编写事务,在事务中使用TRY / CATCH块或者事务是否在TRY块内是正确/最佳实践吗?
此脚本中的重要因素是用户必须手动提交事务。
答案 0 :(得分:40)
只有在TRY
块内并且在实际语句之前,才会打开事务,并立即提交。不要等待控件转到批处理结束以提交事务。
如果在TRY
块中出现问题并且您已打开事务,则控件将跳转到CATCH
块。只需在那里回滚您的交易,并根据需要进行其他错误处理。
在实际回滚事务之前,我已使用@@TRANCOUNT
函数为任何打开的事务添加了一点检查。在这种情况下,它并没有多大意义。在打开事务之前,在TRY
块中进行一些验证检查更有用,例如检查参数值和其他内容,如果任何验证检查失败,则会在TRY
块中引发错误。在这种情况下,控件将跳转到CATCH
块,甚至不会打开事务。在那里你可以检查任何打开的交易和回滚,如果有任何打开的。在您的情况下,您实际上不需要检查任何打开的事务,因为除非您的事务中出现问题,否则您将不会进入CATCH
块。
执行DELETE
操作后,不要询问是否需要提交或回滚;在打开交易之前进行所有这些验证。一旦打开一个事务,立即提交它,如果有任何错误,请进行错误处理(通过使用几乎所有错误函数获取详细信息,你做得很好)。
BEGIN TRY
BEGIN TRANSACTION SCHEDULEDELETE
DELETE -- delete commands full SQL cut out
DELETE -- delete commands full SQL cut out
DELETE -- delete commands full SQL cut out
COMMIT TRANSACTION SCHEDULEDELETE
PRINT 'X rows deleted. Operation Successful Tara.' --calculation cut out.
END TRY
BEGIN CATCH
IF (@@TRANCOUNT > 0)
BEGIN
ROLLBACK TRANSACTION SCHEDULEDELETE
PRINT 'Error detected, all changes reversed'
END
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
END CATCH
答案 1 :(得分:3)
除了上面M.Ali和院长的好建议之外,对于那些希望在SQL SERVER中使用新的(呃)TRY CATCH THROW范例的人来说有点帮助:
(我无法轻易找到完整的语法,因此请在此处添加)
GIST:HERE
此处的示例存储过程代码(来自我的要点):
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
CREATE PROC [dbo].[pr_ins_test]
@CompanyID INT
AS
SET NOCOUNT ON
BEGIN
DECLARE @PreviousConfigID INT
BEGIN TRY
BEGIN TRANSACTION MYTRAN; -- Give the transaction a name
SELECT 1/0 -- Generates divide by zero error causing control to jump into catch
PRINT '>> COMMITING'
COMMIT TRANSACTION MYTRAN;
END TRY
BEGIN CATCH
IF @@TRANCOUNT > 0
BEGIN
PRINT '>> ROLLING BACK'
ROLLBACK TRANSACTION MYTRAN; -- The semi-colon is required (at least in SQL 2012)
END
THROW
END CATCH
END
答案 2 :(得分:2)
永远不要等待最终用户提交事务,除非它是单用户模式数据库。
简而言之,它是关于阻止的。您的事务将对正在更新的资源进行一些独占锁定,并将保留这些锁定,直到事务结束(已提交或回滚)。没有人能够触摸这些行。如果快照隔离与版本存储清理一起使用,则存在一些不同的问题。
最好首先发出一个选择查询以确定多个符合条件的行,将其呈现给最终用户,并在确认后进行实际删除。