xact_abort가 켜져 있을 때 raise 오류가 발생한 후 SQL Server가 계속 실행되는 이유는 무엇입니까?
TSQL에 있는 것 때문에 깜짝 놀랐습니다.만약 xact_abort가 켜져 있다면, 다음과 같은 것을 부르는 것이라고 생각했습니다.
raiserror('Something bad happened', 16, 1);
저장 프로시저(또는 모든 배치)의 실행을 중지합니다.
하지만 제 ADO.NET 오류 메시지는 그 반대였습니다.예외 메시지에 발생한 raise 오류 메시지와 그 다음에 발생한 오류 메시지가 모두 표시되었습니다.
이것은 저의 해결 방법입니다(어쨌든 제 습관입니다). 하지만 그럴 필요는 없을 것 같습니다.
if @somethingBadHappened
begin;
raiserror('Something bad happened', 16, 1);
return;
end;
의사들은 다음과 같이 말합니다.
SET XACT_ABORT가 ON일 때 Transact-SQL 문이 런타임 오류를 발생시키면 전체 트랜잭션이 종료되고 롤백됩니다.
제가 명시적인 거래를 사용해야 한다는 뜻인가요?
이는 유사한 질문에 대한 SQL Server 팀의 응답별 연결에서 볼 수 있듯이 설계 기준입니다TM.
당신의 피드백에 감사드립니다.XACT_ABORT set 옵션은 설계상 RAISERROR 문의 동작에 영향을 주지 않습니다.향후 SQL Server 릴리스를 위해 이 동작을 수정하기 위해 귀하의 의견을 고려해 보겠습니다.
네, 이것은 어떤 사람들에게는 약간의 문제입니다.RAISERROR
높은 심각도로(와 같은)16
)는 SQL 실행 오류와 동일하지만 그렇지 않습니다.
해결 방법은 수행해야 하는 작업에 불과하며, 명시적인 트랜잭션을 사용해도 변경하려는 동작에 영향을 주지 않습니다.
시도/캐치 블록을 사용하는 경우 심각도가 11-19인 상승 오류 번호로 인해 실행이 캐치 블록으로 점프합니다.
16을 초과하는 심각도는 시스템 오류입니다.다음 코드를 시연하려면 시도/캐치 블록을 설정하고 실패할 것으로 예상되는 저장 프로시저를 실행합니다.
자리가 있다고 가정합니다.[Errors](오류) - 저장 프로시저 [dbo]가 있다고 가정합니다.실행 시 실패하는 [AssumeThisFails]
-- first lets build a temporary table to hold errors
if (object_id('tempdb..#RAISERRORS') is null)
create table #RAISERRORS (ErrorNumber int, ErrorMessage varchar(400), ErrorSeverity int, ErrorState int, ErrorLine int, ErrorProcedure varchar(128));
-- this will determine if the transaction level of the query to programatically determine if we need to begin a new transaction or create a save point to rollback to
declare @tc as int;
set @tc = @@trancount;
if (@tc = 0)
begin transaction;
else
save transaction myTransaction;
-- the code in the try block will be executed
begin try
declare @return_value = '0';
set @return_value = '0';
declare
@ErrorNumber as int,
@ErrorMessage as varchar(400),
@ErrorSeverity as int,
@ErrorState as int,
@ErrorLine as int,
@ErrorProcedure as varchar(128);
-- assume that this procedure fails...
exec @return_value = [dbo].[AssumeThisFails]
if (@return_value <> 0)
raiserror('This is my error message', 17, 1);
-- the error severity of 17 will be considered a system error execution of this query will skip the following statements and resume at the begin catch block
if (@tc = 0)
commit transaction;
return(0);
end try
-- the code in the catch block will be executed on raiserror("message", 17, 1)
begin catch
select
@ErrorNumber = ERROR_NUMBER(),
@ErrorMessage = ERROR_MESSAGE(),
@ErrorSeverity = ERROR_SEVERITY(),
@ErrorState = ERROR_STATE(),
@ErrorLine = ERROR_LINE(),
@ErrorProcedure = ERROR_PROCEDURE();
insert #RAISERRORS (ErrorNumber, ErrorMessage, ErrorSeverity, ErrorState, ErrorLine, ErrorProcedure)
values (@ErrorNumber, @ErrorMessage, @ErrorSeverity, @ErrorState, @ErrorLine, @ErrorProcedure);
-- if i started the transaction
if (@tc = 0)
begin
if (XACT_STATE() <> 0)
begin
select * from #RAISERRORS;
rollback transaction;
insert into [dbo].[Errors] (ErrorNumber, ErrorMessage, ErrorSeverity, ErrorState, ErrorLine, ErrorProcedure)
select * from #RAISERRORS;
insert [dbo].[Errors] (ErrorNumber, ErrorMessage, ErrorSeverity, ErrorState, ErrorLine, ErrorProcedure)
values (@ErrorNumber, @ErrorMessage, @ErrorSeverity, @ErrorState, @ErrorLine, @ErrorProcedure);
return(1);
end
end
-- if i didn't start the transaction
if (XACT_STATE() = 1)
begin
rollback transaction myTransaction;
if (object_id('tempdb..#RAISERRORS') is not null)
insert #RAISERRORS (ErrorNumber, ErrorMessage, ErrorSeverity, ErrorState, ErrorLine, ErrorProcedure)
values (@ErrorNumber, @ErrorMessage, @ErrorSeverity, @ErrorState, @ErrorLine, @ErrorProcedure);
else
raiserror(@ErrorMessage, @ErrorSeverity, @ErrorState);
return(2);
end
else if (XACT_STATE() = -1)
begin
rollback transaction;
if (object_id('tempdb..#RAISERRORS') is not null)
insert #RAISERRORS (ErrorNumber, ErrorMessage, ErrorSeverity, ErrorState, ErrorLine, ErrorProcedure)
values (@ErrorNumber, @ErrorMessage, @ErrorSeverity, @ErrorState, @ErrorLine, @ErrorProcedure);
else
raiserror(@ErrorMessage, @ErrorSeverity, @ErrorState);
return(3);
end
end catch
end
사용하다RETURN
직후에RAISERROR()
더 이상 절차를 수행하지 않을 것입니다.
문서에 지적된 바와 같이,THROW
대신 문을 사용해야 합니다.RAISERROR
.
그 둘은 약간 다르게 행동합니다.하지만 언제XACT_ABORT
ON으로 설정된 경우 항상 다음을 사용해야 합니다.THROW
지휘권
마이크로소프트는 에러를 올리는 대신 던지기를 사용할 것을 제안합니다.XACT_State를 사용하여 시도 캐치 블록에 대한 커밋 또는 롤백 결정
set XACT_ABORT ON;
BEGIN TRY
BEGIN TRAN;
insert into customers values('Mark','Davis','markdavis@mail.com', '55909090');
insert into customer values('Zack','Roberts','zackroberts@mail.com','555919191');
COMMIT TRAN;
END TRY
BEGIN CATCH
IF XACT_STATE()=-1
ROLLBACK TRAN;
IF XACT_STATE()=1
COMMIT TRAN;
SELECT ERROR_MESSAGE() AS error_message
END CATCH
언급URL : https://stackoverflow.com/questions/76346/why-does-sql-server-keep-executing-after-raiserror-when-xact-abort-is-on
'programing' 카테고리의 다른 글
JAGS에서 '계수 프로세스' 형태로 파라메트릭 생존 모델 표현 (0) | 2023.06.08 |
---|---|
종속성 속성.등록() 또는 .첨부() 등록 (0) | 2023.06.03 |
CSS 선택기 "~"는 무엇을 의미합니까? (0) | 2023.06.03 |
테스트 환경에서 Rails 콘솔을 실행하고 test_helper.rb를 로드하는 방법은 무엇입니까? (0) | 2023.06.03 |
Ruby에서 정규식의 모든 항목을 일치시키는 방법 (0) | 2023.06.03 |