SQL Server-트랜잭션이 오류로 롤백됩니까?


193

다음과 같은 SQL Server 2005에서 일부 SQL을 실행하는 클라이언트 앱이 있습니다.

BEGIN TRAN;
INSERT INTO myTable (myColumns ...) VALUES (myValues ...);
INSERT INTO myTable (myColumns ...) VALUES (myValues ...);
INSERT INTO myTable (myColumns ...) VALUES (myValues ...);
COMMIT TRAN;

하나의 긴 문자열 명령으로 전송됩니다.

삽입 중 하나가 실패하거나 명령의 일부가 실패하면 SQL Server가 트랜잭션을 롤백합니까? 롤백되지 않으면 롤백하기 위해 두 번째 명령을 보내야합니까?

사용중인 API 및 언어에 대한 세부 정보를 제공 할 수 있지만 SQL Server는 모든 언어에 대해 동일하게 응답해야한다고 생각합니다.


답변:


205

set xact_abort on트랜잭션이 발생하면 오류 발생시 SQL이 자동으로 롤백되도록 할 수 있습니다 .


1
이것은 MS SQL 2K 이상에서 작동합니까? 이것은 가장 간단한 해결책 인 것 같습니다.
jonathanpeppers 2016

1
2000, 2005 및 2008 문서에 표시되므로 예라고 가정합니다. 우리는 2008 년에 그것을 사용하고 있습니다.

8
이 기능을 해제해야합니까, 아니면 세션 당입니까?
Marc

5
@Marc의 범위 xact_abort는 연결 수준에 있습니다.
Keith

2
@AlexMcMillan DROP PROCEDURE 문은 데이터와 함께 작동하는 INSERT와 달리 데이터베이스 구조를 수정합니다. 따라서 트랜잭션으로 랩핑 할 수 없습니다. 지나치게 단순화하고 있지만 기본적으로 그 방법입니다.
eksortso

195

전체 트랜잭션이 롤백 될 것입니다. 명령을 실행하여 롤백해야합니다.

TRY CATCH다음과 같이 이것을 블록으로 감쌀 수 있습니다

BEGIN TRY
    BEGIN TRANSACTION

        INSERT INTO myTable (myColumns ...) VALUES (myValues ...);
        INSERT INTO myTable (myColumns ...) VALUES (myValues ...);
        INSERT INTO myTable (myColumns ...) VALUES (myValues ...);

    COMMIT TRAN -- Transaction Success!
END TRY
BEGIN CATCH
    IF @@TRANCOUNT > 0
        ROLLBACK TRAN --RollBack in case of Error

    -- you can Raise ERROR with RAISEERROR() Statement including the details of the exception
    RAISERROR(ERROR_MESSAGE(), ERROR_SEVERITY(), 1)
END CATCH

2
나는 DyingCactus의 솔루션을 더 좋아합니다. 그는 1 줄의 코드를 변경합니다. 어떤 이유로 든 더 나은 (또는 더 신뢰할 수있는) 경우 알려주세요.
jonathanpeppers 2016

14
try catch는 오류를 캡처 (및 수정 가능)하고 필요한 경우 사용자 정의 오류 메시지를 발생시키는 기능을 제공합니다.
Raj More

11
"캡처 및 수정"보다 "캡처 및 수정"이 더 자주 생각됩니다.
quillbreaker

24
RAISERROR의 구문은 SQL Server 2008R2 이상에서 올바르지 않습니다. 올바른 구문 은 msdn.microsoft.com/en-us/library/ms178592.aspx 를 참조 하십시오 .
Eric J.

2
@BornToCode 트랜잭션이 존재하는지 확인합니다. 주어진 조건 ()에서 트랜잭션을 롤백 try했지만 코드가 실패 한다고 가정합니다 . 더 이상 거래가 없지만 여전히로 이동 중 catch입니다.
가브리엘 GM

42

다음은 MSSQL Server 2016에서 작동하는 오류 메시지가 나오는 코드입니다.

BEGIN TRY
    BEGIN TRANSACTION 
        -- Do your stuff that might fail here
    COMMIT
END TRY
BEGIN CATCH
    IF @@TRANCOUNT > 0
        ROLLBACK TRAN

        DECLARE @ErrorMessage NVARCHAR(4000) = ERROR_MESSAGE()
        DECLARE @ErrorSeverity INT = ERROR_SEVERITY()
        DECLARE @ErrorState INT = ERROR_STATE()

    -- Use RAISERROR inside the CATCH block to return error  
    -- information about the original error that caused  
    -- execution to jump to the CATCH block.  
    RAISERROR (@ErrorMessage, @ErrorSeverity, @ErrorState);
END CATCH

1
DECLARE @Var TYPE; SET @Var = ERROR;SQL Server 2005에서 오류 발생에 사용해야 했습니다. 그렇지 않으면 오류를 발생시키는 위의 코드가 이전 DB에서도 작동합니다. 로컬 변수에 기본값을 할당하려고하면 문제가 발생합니다.
jtlindsey

간단한 THROW를 사용할 수 있습니다. RAISERROR 및 ERROR_ * 선언 대신.
rodzmkii

21

MDSN 기사에서 트랜잭션 제어 (데이터베이스 엔진) .

제약 조건 위반과 같은 런타임 문 오류가 일괄 처리로 발생하면 데이터베이스 엔진의 기본 동작은 오류를 생성 한 문만 롤백하는 것입니다. SET XACT_ABORT 문을 사용하여이 동작을 변경할 수 있습니다. SET XACT_ABORT ON이 실행 된 후 런타임 명령문 오류로 인해 현재 트랜잭션이 자동 롤백됩니다. 구문 오류와 같은 컴파일 오류는 SET XACT_ABORT의 영향을받지 않습니다. 자세한 내용은 SET XACT_ABORT (Transact-SQL)를 참조하십시오.

귀하의 경우 삽입 중 하나라도 실패하면 전체 트랜잭션을 롤백합니다.


3
구문 오류를 어떻게 처리해야합니까? 또는 컴파일 오류? 그 사람이 전체 트랜잭션을 발생하는 경우 롤백해야
MonsterMMORPG

컴파일 / 구문 에러 포착은 SSDT 프로젝트의 목적입니다. :-)
Joe the Coder

10

삽입 중 하나가 실패하거나 명령의 일부가 실패하면 SQL Server가 트랜잭션을 롤백합니까?

아니 그렇지 않아.

롤백되지 않으면 롤백하기 위해 두 번째 명령을 보내야합니까?

물론, ROLLBACK대신 발행해야합니다 COMMIT.

트랜잭션을 커미트 또는 롤백할지 여부를 결정 COMMIT하려면 명령문 에서 문장을 제거 하고 삽입 결과를 점검 한 후 점검 결과에 따라 COMMIT또는 ROLLBACK결과 를 발행 해야합니다.


오류가 발생하면 "기본 키 충돌"이라고 말하고 롤백을 위해 두 번째 전화를 보내야하나요? 나는 그것이 의미가 있다고 생각한다. 매우 오래 실행되는 SQL 문 동안 연결이 끊어지는 등 네트워크 관련 오류가 발생하면 어떻게됩니까?
jonathanpeppers 2016

2
연결 시간이 초과되면 기본 네트워크 프로토콜 (예 : Named Pipes또는 TCP)이 연결을 끊습니다. 연결이 끊어지면 SQL Server현재 실행중인 모든 명령을 중지하고 트랜잭션을 롤백합니다.
Quassnoi

1
DyingCactus의 솔루션은 도움을 주셔서 감사합니다.
jonathanpeppers 2016

당신이에 중단해야하는 경우 어떤 오류, 다음 네, 이것은 최선의 방법입니다.
Quassnoi
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.