문제

이것은 원래 질문에서 상당한 편집으로 기존 답변으로 제기 된 요점을보다 간결하고 다루게합니다.

여러 테이블, 단일 트랜잭션 내부 및 일부 변경 사항 만 롤백으로 변경할 수 있습니까?

아래의 TSQL에서는 "mylogsp"의 변경 사항이 롤백되기를 원하지 않을 것입니다. 그러나 필요한 경우 다양한 mybusinesssps의 모든 변경 사항은 롤백해야합니다.

BEGIN TRANSACTION  

    EXEC myLogSP

    EXEC @err = myBusinessSPa
    IF (@err <> 0) BEGIN ROLLBACK TRANSACTION RETURN -1 END

    EXEC myLogSP

    EXEC @err = myBusinessSPb
    IF (@err <> 0) BEGIN ROLLBACK TRANSACTION RETURN -1 END

    EXEC myLogSP

    EXEC @err = myBusinessSPc
    IF (@err <> 0) BEGIN ROLLBACK TRANSACTION RETURN -1 END

    EXEC myLogSP

COMMIT TRANSACTION
RETURN 0

순서는 중요합니다. myBusinesssps 사이와 후에 MyLogsps가 발생해야합니다 (MyLogsps는 MyBusinesssps의 변경 사항을 픽업합니다).

또한 모든 MyBusinessSP가 데이터베이스 무결성을 유지하기 위해 하나의 트랜잭션 내에서 발생하고 필요한 경우 모든 변경 사항을 롤백으로 허용하는 것이 중요합니다.

마치 MyLogsps가 거래의 일부가 아닌 것처럼 행동하기를 원하는 것처럼 보입니다. 그들이 하나 안에 있다는 것은 불편한 사실 일뿐입니다 (mybusinesssps 사이에 불려질 필요가 있기 때문에).

편집하다:

최종 답변은 "아니오"이며, 유일한 옵션은 코드를 재 설계하는 것입니다. 로깅에 테이블 변수를 사용하는 것 (변수가 롤백되지 않기 때문에) 또는 트랜잭션이 필요하지 않도록 비즈니스 로직을 다시 디자인하는 것입니다 ...

도움이 되었습니까?

해결책

사용 SAVEPOINT에스, 예를 들어

BEGIN TRANSACTION  

    EXEC myLogSP

    SAVE TRANSACTION savepointA
    EXEC @err = myBusinessSPa
    IF (@err <> 0) BEGIN
        ROLLBACK TRANSACTION savepointA
        COMMIT
        RETURN -1
    END

    EXEC myLogSP

    SAVE TRANSACTION savepointB
    EXEC @err = myBusinessSPb
    IF (@err <> 0) BEGIN
        ROLLBACK TRANSACTION savepointB
        COMMIT
        RETURN -1
    END

    EXEC myLogSP

    SAVE TRANSACTION savepointC
    EXEC @err = myBusinessSPc
    IF (@err <> 0) BEGIN
        ROLLBACK TRANSACTION savepointC
        COMMIT
        RETURN -1
    END

    EXEC myLogSP

COMMIT TRANSACTION

편집하다

지금까지 제공된 정보 (및 내 이해)를 기반으로 SPS를 로깅하거나 변수를 사용하거나 파일을 사용하거나 사실 '후'실행을 허용 해야하는 것으로 보입니다. 다음 :

BEGIN TRANSACTION  

    SAVE TRANSACTION savepointA
    EXEC @err = myBusinessSPa
    IF (@err <> 0) BEGIN
        ROLLBACK TRANSACTION savepointA
        EXEC myLogSPA -- the call to myBusinessSPa was attempted/failed
        COMMIT
        RETURN -1
    END

    SAVE TRANSACTION savepointB
    EXEC @err = myBusinessSPb
    IF (@err <> 0) BEGIN
        ROLLBACK TRANSACTION savepointB
        EXEC myLogSPA -- the call to myBusinessSPa originally succeeded
        EXEC myLogSPB -- the call to myBusinessSPb was attempted/failed
        COMMIT
        RETURN -1
    END

    SAVE TRANSACTION savepointC
    EXEC @err = myBusinessSPc
    IF (@err <> 0) BEGIN
        ROLLBACK TRANSACTION savepointC
        EXEC myLogSPA -- the call to myBusinessSPa originally succeeded
        EXEC myLogSPB -- the call to myBusinessSPb originally succeeded
        EXEC myLogSPC -- the call to myBusinessSPc was attempted/failed
        COMMIT
        RETURN -1
    END

    EXEC myLogSPA -- the call to myBusinessSPa succeeded
    EXEC myLogSPB -- the call to myBusinessSPb succeeded
    EXEC myLogSPC -- the call to myBusinessSPc succeeded

COMMIT TRANSACTION

다른 팁

기본적으로 현재 상황을 벗어나야합니다. 그렇게하는 방법에는 몇 가지가 있습니다. 하나 (내가 시도한 적이 없음)는 CLR을 호출하여 인서트를 수행하는 것입니다.

아마도 더 나은 방법은 테이블 변수가 트랜잭션의 영향을받지 않는다는 사실을 사용하는 것입니다. 예를 들어:

CREATE TABLE dbo.Test_Transactions
(
     my_string VARCHAR(20) NOT NULL
)
GO

DECLARE
     @tbl TABLE (my_string VARCHAR(20) NOT NULL)

BEGIN TRANSACTION

INSERT INTO dbo.Test_Transactions (my_string) VALUES ('test point one')

INSERT INTO @tbl (my_string) VALUES ('test point two')

INSERT INTO dbo.Test_Transactions (my_string) VALUES ('test point three')

ROLLBACK TRANSACTION

INSERT INTO dbo.Test_Transactions (my_string) select my_string from @tbl

SELECT * FROM dbo.Test_Transactions
SELECT * FROM @tbl
GO

로그 항목을 테이블 변수에 넣은 다음 커밋 또는 롤백 후 실제 테이블에 삽입하는 데 운이 좋았습니다.

OK SQL Server 2008에 있지 않으면이 방법을 사용해보십시오. 지저분하고 해결 방법이지만 작동해야합니다. #temp 테이블과 테이블 변수는 sp에 의해 반환되는 것의 구조로 설정해야합니다.

create table #templog (fie1d1 int, field2 varchar(10))

declare @templog table (fie1d1 int, field2 varchar(10))

BEGIN TRANSACTION      
insert into #templog
Exec my_proc

insert into @templog (fie1d1, field2)
select t.* from #templog t 
left join @templog t2 on t.fie1d1 = t2.fie1d1 where t2.fie1d1 is null

insert into templog
values (1, 'test')

rollback tran
select * from #templog
select * from templog
select * from @templog

쉬운 방법은 트랜잭션 밖에서 로그 삽입을 이동시키는 것이 아닌가?

테이블 잠금에 대한 답이 없어요. 이미 답이 있다고 생각합니다. 가지다 ID 열이 롤백 될 수 있으므로 테이블 잠금 장치가됩니다.

트랜잭션 시작 명령문을 첫 번째 삽입 후로 이동하십시오.

아마도 자체 원자 트랜잭션 T1의 비즈니스 테이블에 인서트/업데이트를 넣고 롤백없이 로그 테이블 업데이트와 T1 (비즈니스 테이블 업데이트)을 실행하는 다른 트랜잭션 T2에 이러한 각 트랜잭션을 랩핑 할 수 있습니다. 예를 들어:

BEGIN TRANSACTION t2
     <insert to log>
     <execute stored procedure p1>
END TRANSACTION t2

CREATE PROCEDURE p1
AS
     BEGIN TRANSACTION t1
         <insert to business tables>
         <rollback t1 on error>
     END TRANSACTION t1

저장된 절차에서 T1을 롤백 할 때 호출 트랜잭션 T2에 영향을받지 않을 것이라고 생각합니다.

라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top