SQL Server - işlemler hatayı geri alır?


193

Aşağıdaki gibi bir SQL Server 2005'te SQL çalıştıran istemci uygulamamız var:

BEGIN TRAN;
INSERT INTO myTable (myColumns ...) VALUES (myValues ...);
INSERT INTO myTable (myColumns ...) VALUES (myValues ...);
INSERT INTO myTable (myColumns ...) VALUES (myValues ...);
COMMIT TRAN;

Bir uzun dize komutu ile gönderilir.

Eklerden biri başarısız olursa veya komutun herhangi bir bölümü başarısız olursa, SQL Server işlemi geri alır mı? Geri dönmezse, geri almak için ikinci bir komut göndermem gerekir mi?

Kullandığım api ve dil hakkında bilgi verebilirim, ancak SQL Server'ın herhangi bir dil için aynı yanıtı vereceğini düşünürdüm.


Yanıtlar:


205

set xact_abort onHata durumunda sql'in otomatik olarak geri döndüğünden emin olmak için işleminizden önce koyabilirsiniz .


1
Bu MS SQL 2K ve üstü için çalışır mı? Bu en basit çözüm gibi görünüyor.
jonathanpeppers

1
2000, 2005 ve 2008 belgelerinde görünür, bu yüzden evet. 2008'de kullanıyoruz.

8
Kapatmam gerekiyor mu yoksa oturum başına mı?
Marc

5
@Marc'ın kapsamı xact_abortbağlantı seviyesindedir.
Keith

2
@AlexMcMillan DROP PROCEDURE deyimi, yalnızca verilerle çalışan INSERT'ten farklı olarak veritabanı yapısını değiştirir. Bu yüzden bir işleme sarılamaz. Çok basitleştiriyorum, ama temelde böyle.
eksortso

195

Tüm işlemin geri alınacağı konusunda haklısınız. Geri alma komutunu vermelisiniz.

Bunu TRY CATCHaşağıdaki gibi bir blokta sarabilirsiniz

BEGIN TRY
    BEGIN TRANSACTION

        INSERT INTO myTable (myColumns ...) VALUES (myValues ...);
        INSERT INTO myTable (myColumns ...) VALUES (myValues ...);
        INSERT INTO myTable (myColumns ...) VALUES (myValues ...);

    COMMIT TRAN -- Transaction Success!
END TRY
BEGIN CATCH
    IF @@TRANCOUNT > 0
        ROLLBACK TRAN --RollBack in case of Error

    -- you can Raise ERROR with RAISEERROR() Statement including the details of the exception
    RAISERROR(ERROR_MESSAGE(), ERROR_SEVERITY(), 1)
END CATCH

2
DyingCactus'un çözümünü daha iyi seviyorum, değiştirmek için 1 kod satırı. Eğer sizinkinden herhangi bir nedenle daha iyi (ya da daha güvenilir) varsa bana bildirin.
jonathanpeppers

14
Try catch, hatayı yakalama (ve muhtemelen düzeltme) ve gerekirse özel bir hata mesajı oluşturma olanağı sağlar.
Raj More

11
"Yakala ve kaydet" daha sık "yakala ve düzelt" diye düşünüyorum.
quillbreaker

24
RAISERROR sözdizimi en azından SQL Server 2008R2 ve sonrasında yanlıştır. Doğru sözdizimi için bkz. Msdn.microsoft.com/en-us/library/ms178592.aspx .
Eric

2
@BornToCode Işlemin var olduğundan emin olmak için .. Diyelim ki işleminizi belirtilen koşulda (içinde try) geri aldınız , ancak kod başarısız oluyor. Daha fazla işlem yok, ama hala içine giriyorsunuz catch.
Gabriel GM

42

MSSQL Server 2016 ile çalışan hata mesajını alma kodu:

BEGIN TRY
    BEGIN TRANSACTION 
        -- Do your stuff that might fail here
    COMMIT
END TRY
BEGIN CATCH
    IF @@TRANCOUNT > 0
        ROLLBACK TRAN

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

    -- Use RAISERROR inside the CATCH block to return error  
    -- information about the original error that caused  
    -- execution to jump to the CATCH block.  
    RAISERROR (@ErrorMessage, @ErrorSeverity, @ErrorState);
END CATCH

1
Ben DECLARE @Var TYPE; SET @Var = ERROR;sql server 2005 yükseltme hataları için kullanmak zorunda kaldı . Aksi takdirde hata yükseltme için yukarıdaki kod çok eski DB's için çalışır. Soruna neden olan şey, yerel bir değişkene varsayılan bir değer atamaya çalışmaktır.
jtlindsey

Basit bir THROW kullanabilirsiniz; RAISERROR ve ERROR_ * bildirimleri yerine.
rodzmkii

21

MDSN makalesinde, İşlemleri Denetleme (Veritabanı Altyapısı) .

Bir toplu işte çalışma zamanı deyimi hatası (bir kısıtlama ihlali gibi) oluşursa, Veritabanı Altyapısı'nda varsayılan davranış, yalnızca hatayı oluşturan deyimi geri almaktır. Bu davranışı SET XACT_ABORT deyimini kullanarak değiştirebilirsiniz. SET XACT_ABORT ON çalıştırıldıktan sonra, tüm çalışma zamanı deyimi hataları geçerli işlemin otomatik olarak geri alınmasına neden olur. Sözdizimi hataları gibi derleme hataları SET XACT_ABORT tarafından etkilenmez. Daha fazla bilgi için, bkz. SET XACT_ABORT (Transact-SQL).

Sizin durumunuzda, herhangi bir ekleme başarısız olduğunda tüm işlemi geri alır.


3
sözdizimi hatalarını işlemek için neye ihtiyacımız var? veya derleme hataları? herhangi biri olursa tüm işlem geri alınmalıdır
MonsterMMORPG

SSDT projelerinin amacı derleme / sözdizimi hatalarını yakalamaktır. :-)
Kodlayıcı Joe

10

Eklerden biri başarısız olursa veya komutun herhangi bir bölümü başarısız olursa, SQL sunucusu işlemi geri alır mı?

Hayır.

Geri dönmezse, geri almak için ikinci bir komut göndermem gerekir mi?

Tabii, ROLLBACKbunun yerine vermelisin COMMIT.

İşlemin yapılmasına veya geri alınmasına karar vermek istiyorsanız, COMMITcümleyi beyandan çıkarmalı, eklerin sonuçlarını kontrol etmeli ve sonra ya COMMITda ROLLBACKkontrolün sonuçlarına bağlı olarak ya vermelisiniz .


Eğer bir hata alırsam, "Birincil anahtar çakışması" deyin, geri almak için ikinci bir çağrı göndermek gerekir? Sanırım bu mantıklı. Çok uzun süre çalışan bir SQL deyimi sırasında bağlantı kopmuş gibi ağla ilgili bir hata varsa ne olur?
jonathanpeppers

2
Bir bağlantı zaman aşımına uğradığında, temel ağ protokolü (örn. Named PipesVeya TCP) bağlantıyı keser. Bir bağlantı kesildiğinde, o SQL Serveranda çalışan tüm komutları durdurur ve işlemi geri alır.
Quassnoi

1
Bu yüzden DyingCactus'un çözümü sorunumu düzeltiyor gibi görünüyor, yardım için teşekkürler.
jonathanpeppers

Herhangi bir hatayı iptal etmeniz gerekiyorsa , evet, bu en iyi seçenektir.
Quassnoi
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.