it-swarm.com.de

Verwenden Sie keine Transaktion für gespeicherte Prozeduren

Ich habe eine gespeicherte Prozedur, die einige Befehle ausführt. Ich möchte nicht, dass diese Befehle in die Transaktion der gespeicherten Prozedur eingeschlossen werden. Wenn der 4. Befehl fehlschlägt, soll der 1., 2. und 3. Befehl erhalten bleiben und nicht zurückgesetzt werden.

Ist es möglich, die gespeicherte Prozedur so zu schreiben, dass nicht alle als eine große Transaktion ausgeführt werden?

18

Alle Transaktionen werden nicht in einer einzigen Transaktion ausgeführt. Schauen Sie sich dieses Beispiel an:

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;

Hier ist die Ausgabe:

enter image description here

Durch Erstellen einer Sitzung für erweiterte Ereignisse zur Überwachung von sql_transaction Ereignis, hier ist die Ausgabe von der Ausführung von dbo.ChangeValues:

enter image description here

Wie Sie in diesem Screenshot oben sehen können, gibt es für jede der vier Anweisungen separate Transaktionen. Die ersten 3 werden festgeschrieben, und die letzte wird aufgrund des Fehlers zurückgesetzt.

16
Thomas Stringer

Ich denke, es kann hier einige Verwirrung über ein Batch vs ein Transaktion geben.

A Transaktion ist eine Anweisung oder eine Reihe von Anweisungen, die als Einheit entweder erfolgreich sind oder fehlschlagen. Alle DDL-Anweisungen befinden sich in Transaktionen selbst (d. H. Wenn Sie 100 Zeilen aktualisieren, Zeile 98 jedoch einen Fehler auslöst, wird keine der Zeilen aktualisiert). Sie können eine Reihe von Anweisungen auch mit BEGIN TRANSACTION In eine Transaktion einschließen und dann entweder COMMIT oder ROLLBACK.

A batch ist eine Reihe von Anweisungen, die zusammen ausgeführt werden. Eine gespeicherte Prozedur ist ein Beispiel für einen Stapel. Wenn in einer gespeicherten Prozedur eine Anweisung fehlschlägt und eine Fehlerbehebung auftritt (normalerweise TRY/CATCH - Blöcke), werden die nachfolgenden Anweisungen nicht ausgeführt.

Ich vermute, Ihr Problem ist, dass der Stapel abgebrochen wird, wenn ein Fehler auftritt, weil entweder der gespeicherte Prozess selbst oder ein äußerer Bereich (wie die Anwendung oder der gespeicherte Prozess, der diese Prozedur aufruft) eine Fehlerbehebung aufweist. Wenn dies der Fall ist, ist dies schwieriger zu lösen, da Sie anpassen müssen, wie Sie mit Fehlern in dem Bereich umgehen, in dem sie abgefangen werden.

16
JNK

Alles in SQL Server ist in einer Transaktion enthalten.

Wenn Sie explizit begin transaction und end transaction dann heißt es Explizite Transaktion . Wenn Sie dies nicht tun, ist es implizite Transaktion .

Um zu wechseln, in welchem ​​Modus Sie sich befinden, würden Sie verwenden

set implicit_transactions on

oder

set implicit_transactions off

select @@OPTIONS & 2

wenn oben 2 zurückgegeben wird, befinden Sie sich im impliziten Transaktionsmodus. Wenn 0 zurückgegeben wird, befindet sich die automatische Festschreibung.

Eine Transaktion ist ALL oder nichts, um die Datenbank in einem konsistenten Zustand zu halten. Denken Sie an die ACID-Eigenschaften.

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'

- create SP now - Beachten Sie, dass die ersten 3 erfolgreich sind und die vierte aufgrund von Zeichenfolgenkürzungen fehlschlägt ...

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

Siehe: Ist es eine schlechte Praxis, immer eine Transaktion zu erstellen?

8
Kin Shah

So funktionieren gespeicherte Prozeduren standardmäßig. Die gespeicherte Prozedur wird nicht automatisch in eine Transaktion eingeschlossen.

Wenn Sie möchten, dass die gespeicherte Prozedur stoppt, wenn der erste Fehler auftritt, müssen Sie dort eine TRY/CATCH-Anmeldung einfügen, um beispielsweise bei einem Problem mit Befehl 2 zurückzukehren.

3
mrdenny

Sie benötigen für jeden Befehl individuelle Transaktionen. Sie können dies auch mit gespeicherten Transaktionen erreichen:

Siehe SAVE TRANSACTION (Transact-SQL) in der Produktdokumentation.

Ich möchte qualifizieren, dass einzelne Transaktionen das Standardverhalten für gespeicherte Prozeduren sind, da alle Anweisungen in implizite Transaktionen eingeschlossen sind. Niemand sollte sich jedoch auf implizite Transaktionen verlassen, um das Schicksal seines Codes zu kontrollieren. Es ist viel besser, die Art und Weise, wie Transaktionen im Produktionscode behandelt werden, explizit zu steuern.

2
Adam Haines