Non utilizzare una transazione per Stored Procedure


18

Ho una procedura memorizzata che esegue alcuni comandi. Non voglio che questi comandi vengano inseriti nella transazione della procedura memorizzata. Se il 4o comando fallisce, voglio che il 1o, il 2o e il 3o rimangano e non il rollback.

È possibile scrivere la stored procedure in modo tale che non venga eseguita come un'unica grande transazione?

Risposte:


16

Tutte le transazioni non verranno eseguite in un'unica transazione. Dai un'occhiata a questo esempio:

use TestDB;
go

if exists (select 1 from sys.tables where object_id = object_id('dbo.TestTranTable1'))
    drop table dbo.TestTranTable1;
create table dbo.TestTranTable1
(
    id int identity(1, 1) not null,
    some_int int not null
        default 1
);
go

insert into dbo.TestTranTable1
default values;
go 4

select *
from dbo.TestTranTable1;

if exists (select 1 from sys.sql_modules where object_id = object_id('dbo.ChangeValues'))
begin
    drop proc dbo.ChangeValues;
end
go
create proc dbo.ChangeValues
as
    update dbo.TestTranTable1
    set some_int = 11
    where id = 1;

    update dbo.TestTranTable1
    set some_int = 12
    where id = 2;

    update dbo.TestTranTable1
    set some_int = 13
    where id = 3;

    -- this will error out (arithmetic overflow)
    update dbo.TestTranTable1
    set some_int = 2147483648
    where id = 4;
go

exec dbo.ChangeValues;

select *
from dbo.TestTranTable1;

Ecco l'output:

inserisci qui la descrizione dell'immagine

Creando una sessione Eventi estesi per monitorare l' sql_transactionevento, ecco l'output dell'esecuzione dbo.ChangeValues:

inserisci qui la descrizione dell'immagine

Come puoi vedere in questa schermata sopra, ci sono transazioni separate per ciascuna delle quattro dichiarazioni. I primi 3 eseguono il commit e l'ultimo esegue il rollback a causa dell'errore.


16

Penso che qui ci possa essere un po 'di confusione su un batch rispetto a una transazione .

Una transazione è una dichiarazione o una serie di dichiarazioni che avranno successo o falliranno come unità. Tutte le istruzioni DDL sono nelle transazioni stesse (ovvero se aggiorni 100 righe ma la riga 98 genera un errore, nessuna delle righe viene aggiornata). È possibile racchiudere una serie di estratti conto in una transazione utilizzando anche BEGIN TRANSACTIONe quindi o COMMITo ROLLBACK.

Un batch è una serie di istruzioni eseguite insieme. Una procedura memorizzata è un esempio di un batch. In una procedura memorizzata, se un'istruzione non riesce e si verifica un trapping di errori (normalmente TRY/CATCHblocchi), le istruzioni successive non verranno eseguite.

Ho il sospetto che il tuo problema sia che il batch viene annullato quando si verifica un errore perché il proc memorizzato stesso o un ambito esterno (come l'applicazione o il proc memorizzato che chiama questa procedura) contiene un errore. In tal caso, è più difficile da risolvere poiché è necessario regolare il modo in cui si gestiscono gli errori in qualunque ambito li intrappoli.


Non ho trovato nessun articolo che dice "Una procedura di archiviazione è un esempio di batch". Credo che la Stored Procedure sia molto simile al batch ma non è un batch. La differenza principale è: SP è garantito per essere compilato in anticipo e pronto per l'esecuzione più volte a differenza di Batches. Le somiglianze sono: - Entrambi eseguono ciascun comando alla volta. - Se un comando ha avuto esito negativo, tutti i comandi precedenti vengono sottoposti a commit (a meno che non fosse in esecuzione in una transazione) - Se un comando non è riuscito, tutti i comandi successivi non vengono eseguiti.
Ashi,

6

Tutto in SQL Server è contenuto in una transazione.

Quando si specifica esplicitamente begin transactione end transactionquindi si chiama Transazione esplicita . Quando non lo fai, allora è una transazione implicita .

Per cambiare la modalità in cui ti trovi, dovrai usare

set implicit_transactions on

o

set implicit_transactions off

select @@OPTIONS & 2

se sopra restituisce 2, sei in modalità di transazione implicita. Se restituisce 0, sei in autocommit.

Una transazione è TUTTA o nulla per mantenere il database in uno stato coerente .. ricordare le proprietà ACID.

CREATE TABLE [dbo].[Products](
    [ProductID] [int] NOT NULL,
    [ProductName] [varchar](25) NULL,
    [DatabaseName] [sysname] NOT NULL,
 CONSTRAINT [pk_Product_ID_ServerName] PRIMARY KEY CLUSTERED 
(
    [ProductID] ASC,
    [DatabaseName] ASC
)WITH (PAD_INDEX  = OFF, STATISTICS_NORECOMPUTE  = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS  = ON, ALLOW_PAGE_LOCKS  = ON) ON [PRIMARY]
) ON [PRIMARY]

GO


-- insert some data 
INSERT INTO [dbo].[Products]([ProductID], [ProductName], [DatabaseName])
SELECT 1, N'repl1_product1', N'repl1' UNION ALL
SELECT 1, N'repl2_product1_02', N'repl2' UNION ALL
SELECT 1, N'repl3_product1_03', N'repl3' UNION ALL
SELECT 2, N'repl1_product1_01', N'repl1' UNION ALL
SELECT 2, N'repl2_product1', N'repl2' UNION ALL
SELECT 2, N'repl3_product1_03', N'repl3' UNION ALL
SELECT 3, N'repl1_product1_01', N'repl1' UNION ALL
SELECT 3, N'repl2_product1_02', N'repl2' UNION ALL
SELECT 3, N'repl3_product1', N'repl3' UNION ALL
SELECT 4, N'repl1_product1_01', N'repl1' UNION ALL
SELECT 4, N'repl2_product1_02', N'repl2' UNION ALL
SELECT 5, N'repl1_product1_01', N'repl1' UNION ALL
SELECT 5, N'repl2_product1_02', N'repl2'

- crea subito SP - nota che i primi 3 avranno esito positivo e il quarto fallirà a causa del troncamento della stringa ...

IF OBJECT_ID ('usp_UpdateProducts', 'P') IS NOT NULL
    DROP PROCEDURE usp_UpdateProducts;
GO
create procedure usp_UpdateProducts
as 
begin try
update Products 
set ProductName = 'repl1_product1'
where DatabaseName = 'repl1'and ProductID = 1;
update Products
set ProductName = 'repl2_product1'
where DatabaseName = 'repl2' and ProductID = 2;
update Products
set ProductName = 'repl3_product1'
where DatabaseName = 'repl3' and ProductID = 3;
update Products
set ProductName = 'repl3_product1_03&&&&&&&&&&39399338492w9924389234923482' -- this will fail ...
where DatabaseName = 'repl3' and ProductID = 4;
SELECT 1/0;
end try
begin catch
SELECT 
        ERROR_NUMBER() AS ErrorNumber,
        ERROR_SEVERITY() AS ErrorSeverity,
        ERROR_STATE() as ErrorState,
        ERROR_PROCEDURE() as ErrorProcedure,
        ERROR_LINE() as ErrorLine,
        ERROR_MESSAGE() as ErrorMessage;
end catch
go

Fare riferimento a: È una cattiva pratica creare sempre una transazione?


3

Ecco come funzionano le stored procedure per impostazione predefinita. La procedura memorizzata non viene inserita automaticamente in una transazione.

Se si desidera arrestare la procedura memorizzata quando si verifica il primo errore, è necessario inserire alcuni login TRY / CATCH per tornare in caso di un problema con il comando 2, ad esempio.


2

Avrai bisogno di singole transazioni per ciascun comando. Puoi anche farlo con le transazioni salvate:

Vedi SAVE TRANSACTION (Transact-SQL)nella documentazione del prodotto.

Voglio qualificare quelle singole transazioni come comportamento predefinito per le stored procedure, poiché tutte le istruzioni sono racchiuse in transazioni implicite; tuttavia, nessuno dovrebbe fare affidamento su transazioni implicite per controllare il destino del proprio codice. È una pratica molto migliore controllare esplicitamente il modo in cui le transazioni vengono gestite nel codice di produzione.


-2

separare ciascuna delle parti con un TRAN INIZIO e verificare se la transazione è andata a buon fine. se è stato eseguito il commit, altrimenti esegui un rollback, poiché eseguono tutti dallo stesso livello, sarai in grado di eseguire il commit di ogni sezione separatamente senza dover eseguire il rollback di tutti se non ci riesci.

Per maggiori informazioni puoi dare un'occhiata a: http://msdn.microsoft.com/en-us/library/ms188929.aspx


1
Ciò creerà sub-transazioni all'interno della mia Stored Procedure? Idealmente, vorrei evitarlo, se possibile
Matthew Steeples,

1
Se l'SP viene chiamato all'interno di una transazione, le risposte salvate sopra sono la risposta. Se lo sp non viene chiamato con, allora @mrdenny è corretto. Il server SQL non supporta le transazioni nidificate.
StrayCatDBA,

@StrayCatDBA solo per chiarire .. ci sono Transazioni nidificate in SQL Server, ma sono malvagie .. SQL Server consente di avviare transazioni all'interno di altre transazioni, chiamate transazioni nidificate. Fare riferimento alla sqlskills.com/blogs/paul/... , msdn.microsoft.com/en-us/library/ms189336(v=sql.105).aspx e sqlblog.com/blogs/kalen_delaney/archive/2007/08/13 / ...
Kin Shah,

2
Per essere chiari (e per i pigri che non vogliono fare clic sui collegamenti), in realtà non stai avviando un'altra transazione. Alias ​​il titolo sul post di Paul: "Mito: le transazioni nidificate sono reali". Non sono transazioni reali. COMMIT in una transazione nidificata non fa altro che decrementare @@ TRANCOUNT. È vero che non si ottiene un errore se annidate INIZIA TRAN / COMMIT, ma questo è diverso dall'avere reali transizioni nidificate.
StrayCatDBA,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.