Frage

Dies ist ein bedeutender bearbeiten von der ursprünglichen Frage, es prägnanter und Abdecken der Punkte machen, indem vorhandenen Antworten angehoben ...

Ist es möglich, mulitple Änderungen an mehreren Tischen zu haben, in einer einzigen Transaktion und Rollback nur einige der Änderungen?

In der TSQL unten, würde ich will nicht von den Änderungen durch „myLogSP“ zu immer wieder aufgerollt werden. Aber alle von den verschiedenen myBusinessSPs vorgenommenen Änderungen sollten bei Bedarf ein Rollback.

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

Die Reihenfolge wichtig ist, müssen die myLogSPs passieren zwischen und nach den myBusinessSPs (die myLogSPs auf die Veränderungen durch die myBusinessSPs gemacht abholen)

Es ist auch wichtig, dass alle myBusinessSPs innerhalb einer Transaktion passieren die Integrität der Datenbank zu halten und damit alle Änderungen bei Bedarf rückgängig zu machen.

Es ist, als ob ich die myLogSPs will verhalten, als ob sie nicht Teil der Transaktion sind. Es ist nur eine unbequeme Tatsache, dass sie sich gerade innerhalb einer sein (auf Grund benötigen zwischen den myBusinessSPs genannt zu werden.)

EDIT:

endgültige Antwort „nein“ lautet, ist die einzige Möglichkeit ist, den Code neu zu gestalten. Entweder zur Verwendung von Tabellenvariablen für die Protokollierung (als Variablen nicht erhalten zurückgerollt) oder Neugestaltung der Geschäftslogik keine Transaktionen erfordern ...

War es hilfreich?

Lösung

Verwenden Sie SAVEPOINTs , z.

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

Bearbeiten

Basierend auf den Informationen bisher zur Verfügung gestellt (und mein Verständnis davon) scheint es, dass Sie SPs müssen Sie erneut Ingenieur Anmeldung, entweder auf Variablen verwenden, oder Dateien zu verwenden, oder, damit sie ‚nach dem laufen Tatsache‘wie folgt:

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

Andere Tipps

Sie müssen grundsätzlich außerhalb des aktuellen Kontext springen. Es gibt ein paar Möglichkeiten, das zu tun. Ein (die ich noch nie versucht haben) ist es, die CLR anrufen, um den Einsatz zu tun.

Vielleicht ein besserer Weg, obwohl die Tatsache nutzt, dass Tabellenvariablen nicht von Transaktion betroffen ist. Zum Beispiel:

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

Wir haben Glück gehabt mit den Log-Einträge in Tabellenvariablen setzen und Einfügen dann auf die realen Tabellen nach dem Commit oder Rollback.

OK, wenn Sie nicht auf SQL Server 2008 sind, dann versuchen, diese Methode. Es ist chaotisch und eine Abhilfe, aber es sollte funktionieren. Die #temp Tabelle und die Variable würden mit der Struktur aufgebaut werden müssen, was durch die sp zurückgeführt wird.

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

Wäre das nicht der einfache Weg, um die Log-Insertion außerhalb der Transaktion zu bewegen sein?

Ich habe nicht wirklich eine Antwort für Sie für die Tabellensperre, ich glaube, Sie bereits die Antwort haben, wird es wurde eine Tabellensperre sein, weil die Identitätsspalte zurückrollen kann.

bewegen die TRANSACTION-Anweisung nach dem ersten Einsatz BEGIN.

Vielleicht könnten Sie die Einsätze / Aktualisierungen der Business-Tabellen in ihrer eigenen atomaren Transaktion t1 gesetzt und jede dieser Transaktionen in einer anderen Transaktion T2 wickeln, die die Log-Tabelle zu aktualisieren und t1 (die Business-Tabelle Updates) ohne Rollbacks ausführt. Zum Beispiel:

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

Ich glaube, dass, wenn Sie t1 in der gespeicherten Prozedur Rollback dieser die anrufende Transaktion nicht betroffen t2 verlassen wird.

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top