Czy jesteśmy zobowiązani do obsługi transakcji w kodzie C #, a także w procedurze przechowywanej

14

Czy naprawdę potrzebujemy obsługi transakcji w języku c #, a także procesu przechowywania bazy danych po obu stronach

DO#:

Using(transaction with transaction scope)
{
     Execute stored proc;
     Transaction. Complete;
}

Procedura składowana SQL:

Create process
As
Begin try
    Begin transaction
    Commit
End try
Begin catch
    Rollback
End catch
Rakesh Gaur
źródło

Odpowiedzi:

20

Po pierwsze , zawsze powinieneś mieć odpowiednią obsługę transakcji we wszystkich swoich procedurach, aby nie miało znaczenia, czy są one wywoływane przez kod aplikacji, inną procedurę, indywidualnie w zapytaniu ad-hoc, zadaniu agenta SQL lub w inny sposób . Ale pojedyncze instrukcje DML lub kod, który nie wprowadza żadnych modyfikacji, nie wymaga wyraźnej Transakcji. Tak więc polecam:

  • Zawsze miej strukturę TRY / CATCH, aby możliwe było prawidłowe wykreślanie błędów
  • Opcjonalnie dołącz 3 elementy obsługi transakcji do poniższego kodu, jeśli masz wiele instrukcji DML (ponieważ jedna instrukcja jest transakcją samą w sobie). JEDNAK poza dodaniem dodatkowego kodu, który nie jest specjalnie potrzebny, jeśli ktoś woli mieć spójny szablon, nie przeszkadza mu trzymanie w 3 blokach IF związanych z transakcją. Ale w takim przypadku nadal zalecałbym, aby nie przechowywać 3 bloków IF związanych z transakcją dla procesów SELECT tylko (tj. Tylko do odczytu).

Robiąc 2 lub więcej instrukcji DML, musisz użyć czegoś podobnego do następującego (co można również zrobić dla pojedynczych operacji DML, jeśli wolisz być spójny):

CREATE PROCEDURE [SchemaName].[ProcedureName]
(
    @Param  DataType
    ...
)
AS
SET NOCOUNT ON;
DECLARE @InNestedTransaction BIT;

BEGIN TRY

    IF (@@TRANCOUNT = 0)
    BEGIN
        SET @InNestedTransaction = 0;
        BEGIN TRAN; -- only start a transaction if not already in one
    END;
    ELSE
    BEGIN
        SET @InNestedTransaction = 1;
    END;

    -- { 2 or more DML statements (i.e. INSERT / UPDATE / DELETE) }

    IF (@@TRANCOUNT > 0 AND @InNestedTransaction = 0)
    BEGIN
        COMMIT;
    END;

END TRY
BEGIN CATCH

    IF (@@TRANCOUNT > 0 AND @InNestedTransaction = 0)
    BEGIN
        ROLLBACK;
    END;

    DECLARE @ErrorMessage   NVARCHAR(4000) = ERROR_MESSAGE(),
            @ErrorState     INT = ERROR_STATE(),
            @ErrorSeverity  INT = ERROR_SEVERITY();

    -- optionally concatenate ERROR_NUMBER() and/or ERROR_LINE() into @ErrorMessage

    RAISERROR(@ErrorMessage, @ErrorSeverity, @ErrorState);
    RETURN;

END CATCH;

Wykonując tylko 1 instrukcję DML lub po prostu WYBIERZ, możesz uniknąć następujących czynności:

CREATE PROCEDURE [SchemaName].[ProcedureName]
(
    @Param  DataType
    ...
)
AS
SET NOCOUNT ON;

BEGIN TRY

    -- { 0 or 1 DML statements (i.e. INSERT / UPDATE / DELETE) }

END TRY
BEGIN CATCH

    DECLARE @ErrorMessage   NVARCHAR(4000) = ERROR_MESSAGE(),
            @ErrorState     INT = ERROR_STATE(),
            @ErrorSeverity  INT = ERROR_SEVERITY();

    -- optionally concatenate ERROR_NUMBER() and/or ERROR_LINE() into @ErrorMessage

    RAISERROR(@ErrorMessage, @ErrorSeverity, @ErrorState);
    RETURN;

END CATCH;

Po drugie , powinieneś obsłużyć transakcję na warstwie aplikacji tylko wtedy, gdy musisz wykonać więcej niż 1 zapytanie / procedurę składowaną i wszystkie muszą być zgrupowane w operację atomową. Wykonanie pojedynczego działania SqlCommand.Execute___musi odbywać się tylko w trybie próbnym / połowowym, ale nie w transakcji.

Ale, czy to boli zrobić Transakcji w warstwie aplikacji, gdy tylko co pojedynczą rozmowę? Jeśli wymaga MSDTC (Microsoft Distributed Transaction Coordinator), jest to trochę trudniejsze w systemie, aby to zrobić na warstwie aplikacji, gdy nie jest to wyraźnie potrzebne. Osobiście wolę unikać transakcji opartych na warstwie aplikacji, chyba że jest to absolutnie konieczne, ponieważ ogranicza to potencjalne transakcje osierocone (jeśli coś poszło nie tak z kodem aplikacji przed zatwierdzeniem lub wycofaniem). Odkryłem również, że czasami utrudnia to debugowanie niektórych sytuacji. Ale powiedział, że jest nie widzę niczego technicznie złego również przeprowadzenie transakcji w warstwie aplikacji przy podejmowaniu pojedynczy procpołączenie; ponownie, pojedyncza instrukcja DML jest własną transakcją i nie wymaga żadnej jawnej obsługi transakcji na żadnej z warstw.

Solomon Rutzky
źródło