حفظ المعاملة مقابل بدء المعاملة (SQL Server) كيفية تداخل المعاملات بشكل جيد

StackOverflow https://stackoverflow.com//questions/9713350

سؤال

لدي إجراء مخزن يحتاج إلى تعيين نقطة حفظ حتى يتمكن، في ظل ظروف معينة، من التراجع عن كل ما فعله وإعادة رمز خطأ إلى المتصل، أو قبوله/الالتزام به وإعادة النجاح إلى المتصل.لكنني أحتاجه للعمل سواء كان المتصل قد بدأ بالفعل معاملة أم لا.المستند مربك للغاية حول هذا الموضوع.هذا ما أعتقد أنه سينجح، لكنني لست متأكدًا من جميع العواقب.

الشيء هو - هذا Stored Procedure (SP) يسمى من قبل الآخرين.لذلك لا أعرف إذا كانوا قد بدأوا الصفقة أم لا ...حتى لو طلبت من المستخدمين بدء معاملة لاستخدام SP الخاص بي، فلا يزال لدي أسئلة حول الاستخدام السليم لـ Save Points ...

سيختبر مقدم الخدمة الخاص بي ما إذا كانت المعاملة قيد التقدم، وإذا لم تكن كذلك، فابدأ بها BEGIN TRANSACTION.إذا كانت المعاملة جارية بالفعل، فسيتم بدلاً من ذلك إنشاء نقطة حفظ بها SAVE TRANSACTION MySavePointName, وحفظ الحقيقة هذا ما فعلته.

ثم إذا اضطررت إلى التراجع عن التغييرات التي أجريتها، إذا قمت بذلك BEGIN TRANSACTION في وقت سابق، ثم سأفعل ROLLBACK TRANSACTION.إذا قمت بنقطة الحفظ، فسوف أفعل ذلك ROLLBACK TRANSACTION MySavePointName.يبدو أن هذا السيناريو يعمل بشكل رائع.

هذا هو المكان الذي أشعر فيه بالارتباك قليلاً - إذا كنت أرغب في الاحتفاظ بالعمل الذي قمت به، وإذا بدأت معاملة فسوف أقوم بتنفيذها COMMIT TRANSACTION.ولكن إذا قمت بإنشاء نقطة حفظ؟حاولت COMMIT TRANSACTION MySavePointName, ، ولكن بعد ذلك يحاول المتصل تنفيذ معاملته ويحصل على خطأ:

لا يحتوي طلب "إجراء المعاملة" على "بدء المعاملة" المقابلة.

لذلك أتساءل إذن - يمكن التراجع عن نقطة الحفظ (وهذا يعمل: ROLLBACK TRANSACTION MySavePointName لن يتم التراجع عن معاملة المتصل).ولكن ربما لا يحتاج المرء أبدًا إلى "ارتكاب" ذلك؟إنها تظل هناك، في حالة احتياجك إلى العودة إليها، ولكنها تختفي بمجرد الالتزام بالمعاملة الأصلية (أو التراجع عنها)؟

إذا كانت هناك طريقة "أفضل" "لدمج" المعاملة، فيرجى إلقاء بعض الضوء عليها أيضًا.لم أكتشف كيفية التعشيش مع BEGIN TRANSACTION ولكن فقط التراجع عن معاملتي الداخلية أو الالتزام بها.يبدو ROLLBACK سوف يعود دائمًا إلى المعاملة العليا، بينما COMMIT يتناقص ببساطة @@trancount.

هل كانت مفيدة؟

المحلول

أعتقد أنني فهمت كل هذا الآن، لذا سأجيب على سؤالي بنفسي...

لقد قمت بتدوين النتائج التي توصلت إليها إذا كنت تريد المزيد من التفاصيل على http://geekswithblogs.net/bbiales/archive/2012/03/15/how-to-nest-transactions-nicely---quotbegin-transactionquot-vs-quotsave.aspx

لذلك يبدأ SP الخاص بي بشيء من هذا القبيل، لبدء معاملة جديدة إذا لم يكن هناك أي معاملة، ولكن استخدم نقطة الحفظ إذا كانت قيد التقدم بالفعل:

DECLARE @startingTranCount int
SET @startingTranCount = @@TRANCOUNT

IF @startingTranCount > 0
    SAVE TRANSACTION mySavePointName
ELSE
    BEGIN TRANSACTION
-- …

بعد ذلك، عندما تكون مستعدًا لتنفيذ التغييرات، لن تحتاج إلى الالتزام إلا إذا بدأنا المعاملة بأنفسنا:

IF @startingTranCount = 0
    COMMIT TRANSACTION

وأخيرًا، للتراجع عن التغييرات التي أجريتها حتى الآن:

-- Roll back changes...
IF @startingTranCount > 0
    ROLLBACK TRANSACTION MySavePointName
ELSE
    ROLLBACK TRANSACTION

نصائح أخرى

تمتد إجابة بريان ب.

وهذا يضمن أن اسم نقطة الحفظ فريد ويستخدم ميزات TRY/CATCH/THROW الجديدة في SQL Server 2012.

DECLARE @mark CHAR(32) = replace(newid(), '-', '');
DECLARE @trans INT = @@TRANCOUNT;

IF @trans = 0
    BEGIN TRANSACTION @mark;
ELSE
    SAVE TRANSACTION @mark;

BEGIN TRY
    -- do work here

    IF @trans = 0
        COMMIT TRANSACTION @mark;
END TRY
BEGIN CATCH
    IF xact_state() = 1 OR (@trans = 0 AND xact_state() <> 0) ROLLBACK TRANSACTION @mark;
    THROW;
END CATCH

لقد استخدمت هذا النوع من مدير المعاملات في الإجراءات المخزنة الخاصة بي:

    CREATE PROCEDURE Ardi_Sample_Test  
        @InputCandidateID INT  
    AS  
        DECLARE @TranCounter INT;  
        SET @TranCounter = @@TRANCOUNT;  
        IF @TranCounter > 0  
            SAVE TRANSACTION ProcedureSave;  
        ELSE  
            BEGIN TRANSACTION;  
        BEGIN TRY  

            /*
            <Your Code>
            */

            IF @TranCounter = 0  
                COMMIT TRANSACTION;  
        END TRY  
        BEGIN CATCH  
            IF @TranCounter = 0  
                ROLLBACK TRANSACTION;  
            ELSE  
                IF XACT_STATE() <> -1  
                    ROLLBACK TRANSACTION ProcedureSave;  

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

            RAISERROR (@ErrorMessage, @ErrorSeverity, @ErrorState);  
        END CATCH  
    GO  
مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top