거래 내부에서 이루어진 구체적인 변경 만 롤백 할 수 있습니다.
-
03-07-2019 - |
문제
이것은 원래 질문에서 상당한 편집으로 기존 답변으로 제기 된 요점을보다 간결하고 다루게합니다.
여러 테이블, 단일 트랜잭션 내부 및 일부 변경 사항 만 롤백으로 변경할 수 있습니까?
아래의 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에 영향을받지 않을 것이라고 생각합니다.