トランザクションとtry/catchブロックを持つMS SQLスクリプトを記述しようとしています。例外をキャッチすると、トランザクションはロールバックされます。そうでない場合、トランザクションはコミットされます。私はこのようにすることを言っているいくつかの異なるウェブサイトを見ました:
begin transaction
begin try
--main content of script here
end try
begin catch
rollback transaction
end catch
commit transaction
しかし、例外をキャッチした場合でも、「コミットトランザクション」行にヒットしませんか?トランザクションはすでにロールバックされているため、これはSQLエラーにつながりませんか?私はそれが次のように行われるべきだと思う:
declare @success bit = 1
begin transaction
begin try
--main content of script here
end try
begin catch
rollback transaction
set @success = 0
end catch
if(@success = 1)
begin
commit transaction
end
よく投稿されるソリューションに@success変数が含まれていないのはどうしてですか?すでにロールバックされたトランザクションをコミットした結果として発生するSQLエラーはありませんか?例外をキャッチした場合でも、最初のコード例の「トランザクションのコミット」行がヒットするというのは間違っていますか?
私はいつも これはより良い記事の1つでした について考えました。私はそれを明確にするだろうと思う次の例を含み、信頼できるネストされたトランザクションに必要な見落とされがちな@@ trancountを含む
PRINT 'BEFORE TRY'
BEGIN TRY
BEGIN TRAN
PRINT 'First Statement in the TRY block'
INSERT INTO dbo.Account(AccountId, Name , Balance) VALUES(1, 'Account1', 10000)
UPDATE dbo.Account SET Balance = Balance + CAST('TEN THOUSAND' AS MONEY) WHERE AccountId = 1
INSERT INTO dbo.Account(AccountId, Name , Balance) VALUES(2, 'Account2', 20000)
PRINT 'Last Statement in the TRY block'
COMMIT TRAN
END TRY
BEGIN CATCH
PRINT 'In CATCH Block'
IF(@@TRANCOUNT > 0)
ROLLBACK TRAN;
THROW; -- raise error to the client
END CATCH
PRINT 'After END CATCH'
SELECT * FROM dbo.Account WITH(NOLOCK)
GO
最初の例では、あなたは正しいです。 tryブロックが起動するかどうかに関係なく、バッチはコミットトランザクションをヒットします。
2番目の例では、他のコメント者に同意します。成功フラグを使用する必要はありません。
基本的に、次のアプローチは軽量のベストプラクティスアプローチであると考えています。
例外の処理方法を確認するには、2番目の挿入の値を255から256に変更します。
CREATE TABLE #TEMP ( ID TINYINT NOT NULL );
INSERT INTO #TEMP( ID ) VALUES ( 1 )
BEGIN TRY
BEGIN TRANSACTION
INSERT INTO #TEMP( ID ) VALUES ( 2 )
INSERT INTO #TEMP( ID ) VALUES ( 255 )
COMMIT TRANSACTION
END TRY
BEGIN CATCH
DECLARE
@ErrorMessage NVARCHAR(4000),
@ErrorSeverity INT,
@ErrorState INT;
SELECT
@ErrorMessage = ERROR_MESSAGE(),
@ErrorSeverity = ERROR_SEVERITY(),
@ErrorState = ERROR_STATE();
RAISERROR (
@ErrorMessage,
@ErrorSeverity,
@ErrorState
);
ROLLBACK TRANSACTION
END CATCH
SET NOCOUNT ON
SELECT ID
FROM #TEMP
DROP TABLE #TEMP
Try-Catch、Commit Transaction- Rollback Transaction、Error Trackingを使用するms sqlスクリプトパターンを数回正常に使用しました。
TRYブロックは次のようになります
BEGIN TRY
BEGIN TRANSACTION T
----
//your script block
----
COMMIT TRANSACTION T
END TRY
CATCHブロックは次のようになります
BEGIN CATCH
DECLARE @ErrMsg NVarChar(4000),
@ErrNum Int,
@ErrSeverity Int,
@ErrState Int,
@ErrLine Int,
@ErrProc NVarChar(200)
SELECT @ErrNum = Error_Number(),
@ErrSeverity = Error_Severity(),
@ErrState = Error_State(),
@ErrLine = Error_Line(),
@ErrProc = IsNull(Error_Procedure(), '-')
SET @ErrMsg = N'ErrLine: ' + rtrim(@ErrLine) + ', proc: ' + RTRIM(@ErrProc) + ',
Message: '+ Error_Message()
ROLLBACKスクリプトは、次のようにCATCHブロックの一部になります
IF (@@TRANCOUNT) > 0
BEGIN
PRINT 'ROLLBACK: ' + SUBSTRING(@ErrMsg,1,4000)
ROLLBACK TRANSACTION T
END
ELSE
BEGIN
PRINT SUBSTRING(@ErrMsg,1,4000);
END
END CATCH
上記の異なるスクリプトブロックは、1つのブロックとして使用する必要があります。 TRYブロックでエラーが発生した場合、CATCHブロックに進みます。そこでは、エラー番号、エラーの重大度、エラー行などに関するさまざまな詳細を設定しています。最後に、これらすべての詳細が@ErrMsgパラメーターに追加されます。次に、トランザクションのカウント(@@ TRANCOUNT> 0)をチェックします。つまり、ロールバックのためにトランザクションに何かが存在するかどうかをチェックします。存在する場合は、エラーメッセージとROLLBACK TRANSACTIONを表示します。それ以外の場合は、単にエラーメッセージを出力します。
COMMIT TRANSACTION TスクリプトをTRYブロックの最後の行に向けて保持し、TRYブロック内のすべてのコードが完了した後にのみトランザクション(データベースの最終変更)をコミットするようにします正常に実行されます。
取引カウンター
--@@TRANCOUNT = 0
begin try
--@@TRANCOUNT = 0
BEGIN TRANSACTION tran1
--@@TRANCOUNT = 1
--your code
-- if failed @@TRANCOUNT = 1
-- if success @@TRANCOUNT = 0
COMMIT TRANSACTION tran1
end try
begin catch
print 'FAILED'
end catch
以下が役に立つかもしれません。
ソース: https://msdn.Microsoft.com/en-us/library/ms175976.aspx
BEGIN TRANSACTION;
BEGIN TRY
-- your code --
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;
IF @@TRANCOUNT > 0
ROLLBACK TRANSACTION;
END CATCH;
IF @@TRANCOUNT > 0
COMMIT TRANSACTION;
GO