Domanda

Questa è una modifica significativa della domanda originale, che la rende più concisa e copre i punti sollevati dalle risposte esistenti ...

È possibile apportare modifiche multiple a più tabelle, all'interno di una singola transazione, e ripristinare solo alcune delle modifiche?

Nel TSQL di seguito, NON desidero nessuna delle modifiche apportate da " myLogSP " essere mai ritirato. Ma tutte le modifiche apportate dai vari myBusinessSP dovrebbero tornare indietro, se necessario.

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

L'ordine è importante, i myLogSP devono avvenire tra e dopo i myBusinessSP (i myLogSP raccolgono le modifiche apportate dai myBusinessSP)

È anche importante che tutti i myBusinessSP avvengano all'interno di una transazione per mantenere l'integrità del database e consentire il rollback di tutte le loro modifiche, se necessario.

È come se volessi che myLogSPs si comportasse come se non facessero parte della transazione. È solo un fatto scomodo che si trovino all'interno di uno (in virtù della necessità di essere chiamati tra i myBusinessSP.)

EDIT:

La risposta finale è "no", l'unica opzione è riprogettare il codice. Utilizzare le variabili di tabella per la registrazione (poiché le variabili non vengono ripristinate) o riprogettare la logica aziendale in Non richiedere transazioni ...

È stato utile?

Soluzione

Usa SAVEPOINT s , ad esempio

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

Modifica

Sulla base delle informazioni fornite finora (e della mia comprensione) sembra che dovrai riprogettare i tuoi SP di registrazione, o per utilizzare le variabili, o per utilizzare i file o per consentire loro di eseguire "dopo il fatto 'come segue:

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

Altri suggerimenti

Devi sostanzialmente saltare fuori dal contesto attuale. Ci sono un paio di modi per farlo. Uno (che non ho mai provato) è chiamare il CLR per fare l'inserimento.

Forse un modo migliore è usare il fatto che le variabili della tabella non sono influenzate dalla transazione. Ad esempio:

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

Abbiamo avuto fortuna con l'inserimento delle voci di registro nelle variabili di tabella e l'inserimento nelle tabelle reali dopo il commit o il rollback.

OK se non sei su SQL Server 2008, prova questo metodo. È disordinato e una soluzione alternativa, ma dovrebbe funzionare. La tabella #temp e la variabile table dovrebbero essere configurate con la struttura di ciò che viene restituito dallo 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

Non sarebbe semplice spostare l'inserimento del registro all'esterno della transazione?

Non ho davvero una risposta per te per il blocco della tabella, penso che tu abbia già la risposta, ci sarà avere per essere un blocco della tabella perché il la colonna identità può tornare indietro.

sposta l'istruzione BEGIN TRANSACTION dopo il primo inserimento.

Forse potresti inserire gli inserimenti / aggiornamenti nelle tabelle di business nella loro transazione atomica t1 e racchiudere ciascuna di queste transazioni in un'altra transazione t2 che esegue l'aggiornamento della tabella di registro e t1 (gli aggiornamenti della tabella di business) senza rollback. Ad esempio:

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

Ritengo che quando si esegue il rollback di t1 nella procedura memorizzata, la transazione chiamante t2 non viene modificata.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top