Saklı yordamda işlem


12

Tek bir işlemde bir UPDATE ve bir INSERT gerçekleştirmek gerekir. Bu kod kendi başına iyi çalışıyor, ancak kolayca aramak ve gerekli parametreleri iletmek istiyorum. Saklı bir yordamda bu işlemi iç içe çalıştığımda, çok sayıda sözdizimi hatalarına çalıştırın.

Kolayca çağrılabilmesi için aşağıdaki kodu nasıl ekleyebilirim?

BEGIN TRANSACTION AssignUserToTicket
GO

DECLARE @updateAuthor varchar(100)
DECLARE @assignedUser varchar(100)
DECLARE @ticketID bigint

SET @updateAuthor = 'user1'
SET @assignedUser = 'user2'
SET @ticketID = 123456

    UPDATE tblTicket SET ticketAssignedUserSamAccountName = @assignedUser WHERE (ticketID = @ticketID);
    INSERT INTO [dbo].[tblTicketUpdate]
           ([ticketID]
           ,[updateDetail]
           ,[updateDateTime]
           ,[userSamAccountName]
           ,[activity])
     VALUES
           (@ticketID,
           'Assigned ticket to ' + @assignedUser,
           GetDate(),
           @updateAuthor,
           'Assign');
GO
COMMIT TRANSACTION AssignUserToTicket

1
Sorunuza "hataların" tam olarak ne olduğu hakkında ayrıntılar eklediyseniz büyük olasılıkla yardımcı olacaktır ( sorunuzun altındaki düzenleme bağlantısını kullanın). Ayrıca, lütfen tura katılın . Teşekkürler!
Max Vernon

Yanıtlar:


15

Bu kodu CREATE PROCEDURE ...sözdizimine almanız ve GOifadeleri BEGIN TRANSACTIONönce ve sonra kaldırmanız gerekir COMMIT TRANSACTION.

GO
CREATE PROCEDURE dbo.AssignUserToTicket
(
     @updateAuthor varchar(100)
    , @assignedUser varchar(100)
    , @ticketID bigint
)
AS
BEGIN
    BEGIN TRANSACTION;
    SAVE TRANSACTION MySavePoint;
    SET @updateAuthor = 'user1';
    SET @assignedUser = 'user2';
    SET @ticketID = 123456;

    BEGIN TRY
        UPDATE dbo.tblTicket 
        SET ticketAssignedUserSamAccountName = @assignedUser 
        WHERE (ticketID = @ticketID);

        INSERT INTO [dbo].[tblTicketUpdate]
            (
            [ticketID]
            ,[updateDetail]
            ,[updateDateTime]
            ,[userSamAccountName]
            ,[activity]
            )
        VALUES (
            @ticketID
            , 'Assigned ticket to ' + @assignedUser
            , GetDate()
            , @updateAuthor
            , 'Assign'
            );
        COMMIT TRANSACTION 
    END TRY
    BEGIN CATCH
        IF @@TRANCOUNT > 0
        BEGIN
            ROLLBACK TRANSACTION MySavePoint; -- rollback to MySavePoint
        END
    END CATCH
END;
GO

Ayrıca, bazı hataların meydana TRY...CATCHgelmesi ROLLBACK TRANSACTIONdurumunda bir ifadenin gerçekleştirilmesine izin vermek için bir ifade bloğu ekledim . Muhtemelen bundan daha iyi hata işlemeye ihtiyacınız vardır, ancak gereksinimleriniz hakkında bilgi sahibi olmadan, bu en iyi ihtimalle zordur.

Bazı iyi okumalar:

  1. Her zaman şemayı belirtin

  2. Saklı Yordam En İyi Uygulamaları

  3. Kaçınılması gereken kötü alışkanlıklar


1
Yine de kaydedilmiş bir işleminiz olmasını istiyorsunuz. Bir SP'ye bir işlem koyarsanız ve SP başka bir işleme sarılırsa, işler başarısız olur. sqlstudies.com/2014/01/06/…
Kenneth Fisher

beni ona gösterdiğin için teşekkürler. SQL Server'da iç içe geçmiş işlemler olmadığını biliyorum, ancak SAVE TRANSkomutun etkilerinin farkında değildim .
Max Vernon

8

İşlemleri (T-SQL veya uygulama kodundan başlatılmış olsun) işleyebilen iç içe Saklı Yordamlar'ı doğru şekilde işlemek istiyorsanız, aşağıdaki yanıtta açıkladığım şablonu izlemelisiniz:

İşlemi C # Kodunda ve saklı yordamda işlememiz gerekiyor mu

Burada denediğinizden iki fark göreceksiniz:

  1. Blok RAISERRORiçinde kullanımı CATCH. Bu, hatayı arama düzeyine (DB veya uygulama katmanında olsun) kadar artırır, böylece bir hatanın oluşmasıyla ilgili bir karar verilebilir.

  2. Hayır SAVE TRANSACTION. Bunu kullanmak için hiç bir dava bulamadım. Bazı milletlerin bunu tercih ettiğini biliyorum, ama şimdiye kadar çalıştığım herhangi bir yerde yaptığım her şeyde, iç içe geçmişlerin herhangi birinde meydana gelen bir hata kavramı zaten yapılmış olan her işin geçersiz olduğunu ima etti. Kullanarak SAVE TRANSACTION, yalnızca bu Kayıtlı Prosedür çağrılmadan hemen önceki duruma geri dönersiniz ve mevcut işlemi aksi halde geçerli bırakırsınız.

    Hakkında daha fazla ayrıntı istiyorsanız SAVE TRANSACTION, lütfen bu yanıttaki bilgilere göz atın:

    Bir saklı yordamdan 3 saklı yordam başlatıldığında geri alma

    Başka bir sorun, KAYDET İŞLEMİSAVE TRANSACTION için MSDN sayfasında belirtildiği gibi davranışının bir nüansıdır (vurgu eklendi):

    Bir işlemde yinelenen kayıt noktası adlarına izin verilir, ancak kayıt noktası adını belirten bir ROLLBACK TRANSACTION deyimi, işlemi yalnızca bu adı kullanarak en son KAYDETME işlemine geri döndürür .

    Yani, her Saklı Yordamdaki her Kayıt Noktasına tüm Saklı Yordamlardaki tüm Kaydetme Noktaları arasında benzersiz bir ad vermek için çok dikkatli olmanız gerekir. Aşağıdaki örnekler bu noktayı açıklamaktadır.

    Bu ilk örnek, Kaydetme Noktası adını yeniden kullandığınızda ne olacağını gösterir; yalnızca en düşük düzeydeki Kaydetme Noktası geri alınır.

    IF (OBJECT_ID(N'tempdb..#SaveTranTestA') IS NOT NULL)
    BEGIN
        DROP TABLE #SaveTranTestA;
    END;
    CREATE TABLE #SaveTranTestA (SomeVal INT NOT NULL);
    
    BEGIN TRAN; -- start level 1
    SAVE TRANSACTION MySavePoint;
    
    SELECT @@TRANCOUNT AS [TranCount]; -- 1
    
    INSERT INTO #SaveTranTestA (SomeVal) VALUES (100);
    
    BEGIN TRAN; -- start level 2
    SAVE TRANSACTION MySavePoint;
    
    SELECT @@TRANCOUNT AS [TranCount]; -- 2
    
    INSERT INTO #SaveTranTestA (SomeVal) VALUES (200);
    
    COMMIT; -- exit level 2
    
    SELECT @@TRANCOUNT AS [TranCount]; -- 1
    SELECT * FROM #SaveTranTestA;
    -- 100
    -- 200
    
    ROLLBACK TRANSACTION MySavePoint; -- error occurred; undo actions up to this point
    
    SELECT @@TRANCOUNT AS [TranCount]; -- 1
    SELECT * FROM #SaveTranTestA;
    -- 100
    
    COMMIT; -- exit level 1
    
    SELECT @@TRANCOUNT AS [TranCount]; -- 0
    SELECT * FROM #SaveTranTestA;
    -- 100
    

    Bu ikinci örnek, benzersiz Kaydetme Noktası adları kullandığınızda ne olacağını gösterir; istenen seviyenin Kaydetme Noktası geri alınır.

    IF (OBJECT_ID(N'tempdb..#SaveTranTestB') IS NOT NULL)
    BEGIN
        DROP TABLE #SaveTranTestB;
    END;
    CREATE TABLE #SaveTranTestB (SomeVal INT NOT NULL);
    
    BEGIN TRAN; -- start level 1
    SAVE TRANSACTION MySavePointUno;
    
    SELECT @@TRANCOUNT AS [TranCount]; -- 1
    
    INSERT INTO #SaveTranTestB (SomeVal) VALUES (100);
    
    BEGIN TRAN; -- start level 2
    SAVE TRANSACTION MySavePointDos;
    
    SELECT @@TRANCOUNT AS [TranCount]; -- 2
    
    INSERT INTO #SaveTranTestB (SomeVal) VALUES (200);
    
    COMMIT; -- exit level 2
    
    SELECT @@TRANCOUNT AS [TranCount]; -- 1
    SELECT * FROM #SaveTranTestB;
    -- 100
    -- 200
    
    ROLLBACK TRANSACTION MySavePointUno; --error occurred; undo actions up to this point
    
    SELECT @@TRANCOUNT AS [TranCount]; -- 1
    SELECT * FROM #SaveTranTestB;
    -- <no rows>
    
    COMMIT; -- exit level 1
    
    SELECT @@TRANCOUNT AS [TranCount]; -- 0
    SELECT * FROM #SaveTranTestB;
    -- <no rows>
    

Bu yüzden SAVE TRANSACTION kayıt noktası adımı oluşturmak için @@ NESTLEVEL kullanıyorum.
Vincent Vancalbergh
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.