EXECUTE sonrasındaki işlem sayısı, eşleşmeyen BEGIN ve COMMIT ifadeleri sayısını gösterir. Önceki sayı = 1, mevcut sayı = 0


95

Bir sahip Insertveri akışı saklı yordamı Table1ve elde Column1değeri Table1ve Table2 besleyecek ikinci saklı süreci çağırır.

Ama ikinci saklı yordamı şu şekilde çağırdığımda:

Exec USPStoredProcName

Şu hatayı alıyorum:

EXECUTE sonrasındaki işlem sayısı, eşleşmeyen BEGIN ve COMMIT ifadeleri sayısını gösterir. Önceki sayı = 1, mevcut sayı = 0.

Bu tür diğer sorulardaki cevapları okudum ve kesinleştirme sayısının tam olarak nerede karıştığını bulamıyorum.


Prosedürünüzde herhangi bir TRY / CATCH blokunuz var mı?
Remus Rusanu

Evet TRY / CATCH
bloğum var

Yanıtlar:


110

Bir TRY / CATCH bloğunuz varsa, bunun olası nedeni, bir işlem iptal istisnasını yakalayıp devam etmenizdir. CATCH bloğunda her zaman XACT_STATE()uygun iptal edilmiş ve teslim edilemeyen (mahkum edilmiş) işlemleri kontrol etmeli ve işlemelisiniz. Arayanınız bir işlem başlatırsa ve arayan kişi örneğin bir kilitlenme (işlemi iptal eden) ile karşılaşırsa, aranan uç, arayan kişiye işlemin iptal edildiğini ve 'her zamanki gibi çalışmaya devam etmemesi gerektiğini' nasıl bildirecek? Tek uygulanabilir yol, bir istisnayı yeniden gündeme getirerek arayan kişiyi durumu halletmeye zorlamaktır. Durdurulmuş bir işlemi sessizce yutarsanız ve arayan kişi hala orijinal işlemde olduğunu varsaymaya devam ederse, yalnızca kargaşa bunu sağlayabilir (ve aldığınız hata, motorun kendini korumaya çalışmasıdır).

İç içe geçmiş işlemler ve istisnalarla kullanılabilecek bir model gösteren İstisna işlemeyi ve iç içe geçmiş işlemleri gözden geçirmenizi öneririm :

create procedure [usp_my_procedure_name]
as
begin
    set nocount on;
    declare @trancount int;
    set @trancount = @@trancount;
    begin try
        if @trancount = 0
            begin transaction
        else
            save transaction usp_my_procedure_name;

        -- Do the actual work here

lbexit:
        if @trancount = 0
            commit;
    end try
    begin catch
        declare @error int, @message varchar(4000), @xstate int;
        select @error = ERROR_NUMBER(), @message = ERROR_MESSAGE(), @xstate = XACT_STATE();
        if @xstate = -1
            rollback;
        if @xstate = 1 and @trancount = 0
            rollback
        if @xstate = 1 and @trancount > 0
            rollback transaction usp_my_procedure_name;

        raiserror ('usp_my_procedure_name: %d: %s', 16, 1, @error, @message) ;
    end catch
end
go

3
Yardımınız için teşekkürler. Raiserror kullanarak sorunu buldum. NOT NULL alanına NULL değeri eklemeye çalışmakla ilgili
Vignesh Kumar A

Ancak kısıtlama denetimi doğrulaması işlemi iptal etmez. Açıkça yakalamada geri mi dönüyorsunuz yoksa kullanıyor xact_abort onmusunuz?
Remus Rusanu

Açıkça geri dönüyor
Vignesh Kumar

2
Bu modeli denedim ama yine de çalışmıyor - harici bir işlemim olduğunda bu model bir kayıt noktası oluşturuyor ve kritik bir hata durumunda (başa çıkılamayan işlem) dış işlemi geri alıyor - bu yine de girmeden önce @@ trancount = 1'e neden oluyor prosedür ve @@ trancount = 0'dan çıkarken
serçe

3
Ben CATCH bu biraz yanlış olduğunu düşünüyorum: if @xstate = -1 rollback; Bu baktığımızda MSDN Örneğin , biz gereken değil olmadıkça tam İşlem geri değil bir dış işlem (yaptığımız olduğunu, sürece begin tran). Bence işlem sadece rollback@ sparrow'un problemini çözecek işlemi başlatırsak yapılmalı .
Nick

62

Ben de bu problemi yaşadım. Benim için sebebi yapıyordum

return
commit

onun yerine

commit
return   

tek bir saklı yordamda.


4
@seguso - bu çok yardımcı oldu. Paylaşım için teşekkürler. Bazen bir şey tozun altına çok basitçe girer. En iyilerine de oluyor.
Leo Gurdian

Bu benim için problemdi, ancak daha az açıktı çünkü veri erişim katmanımız aracılığıyla birkaç sproc aramasını tek bir büyük işlemde sarıyorduk - yani sadece sproc'a baktığınızda bir işlem olduğunu söyleyemezdiniz. Bu sorunu yaşıyorsanız, sproc'un dışında bir işlem oluşturan bir şey olmadığından emin olun. Varsa, sproc içinde return deyimlerini hiç kullanamayabilirsiniz.
EF0

Bu bendim, bir işlem yaptım ve taahhüt işlemimden önce if / else ifadesiyle geri dönüyordum
Kevin

19

Bu normalde işlem başlatıldığında ve taahhüt edilmediğinde veya geri alınmadığında gerçekleşir.

Hatanın saklı yordamınızda gelmesi durumunda, bu veritabanı tablolarını kilitleyebilir çünkü istisna işleme olmadığında bazı çalışma zamanı hataları nedeniyle işlem tamamlanamaz. İstisna işlemeyi aşağıdaki gibi kullanabilirsiniz. XACT_ABORT AYARLA

SET XACT_ABORT ON
SET NoCount ON
Begin Try 
     BEGIN TRANSACTION 
        //Insert ,update queries    
     COMMIT
End Try 
Begin Catch 
     ROLLBACK
End Catch

Kaynak


Eğer durum böyleyse, belirtilen soru / cevap muhtemelen bunun yinelenen olarak işaretlenmesi ve kapatılması gerektiği anlamına gelmelidir
Mark Schultheiss

10

İç içe geçmiş işlemler kullanırsanız, bir ROLLBACK işleminin en dıştaki dahil tüm iç içe geçmiş işlemleri geri aldığını unutmayın.

Bu, TRY / CATCH ile birlikte kullanıldığında, tanımladığınız hatayla sonuçlanabilir. Daha fazlasını burada görün .


5

Bu, bir işlemi açtıktan sonra saklı yordamınız bir derleme hatasıyla karşılaşırsa da oluşabilir (örneğin, tablo bulunamadı, geçersiz sütun adı).

Remus Rusanu tarafından özetlenen mantığa benzer bir mantıkla 2 saklı yordamı, bir "çalışan" ve bir sarmalayıcıyı kullanmak zorunda olduğumu fark ettim. İşçi yakalama "normal" hataları işlemek için kullanılır ve sarmalayıcı yakalama derleme hatası hatalarını işlemek için kullanılır.

https://msdn.microsoft.com/en-us/library/ms175976.aspx

Bir TRY'den Etkilenmeyen Hatalar… CATCH Construct

Aşağıdaki hata türleri , TRY… CATCH yapısıyla aynı yürütme düzeyinde meydana geldiklerinde bir CATCH bloğu tarafından işlenmez :

  • Bir grubun çalışmasını engelleyen sözdizimi hataları gibi hataları derleyin .
  • Ertelenen ad çözümlemesi nedeniyle derlemeden sonra oluşan nesne adı çözümleme hataları gibi ifade düzeyinde yeniden derleme sırasında oluşan hatalar.

Umarım bu, başka birinin birkaç saatlik hata ayıklamadan tasarruf etmesine yardımcı olur ...


1
Teşekkürler Justin. Güzel gözlem. Benim durumumda, SP kaydetme sırasında derleme hataları üretmeyen ancak gerçekten geçersiz sözdizimi olan bir güncelleme içinde bir toplama yapıyordum - "Bir UPDATE ifadesinin küme listesinde bir toplam görünmeyebilir"
kuklei

4

Benim durumumda, hata bir neden ediliyordu RETURNiçeride BEGIN TRANSACTION. Bu yüzden şöyle bir şey yaşadım:

Begin Transaction
 If (@something = 'foo')
 Begin
     --- do some stuff
     Return
 End
commit

ve olması gerekir:

Begin Transaction
 If (@something = 'foo')
 Begin
     --- do some stuff
     Rollback Transaction ----- THIS WAS MISSING
     Return
 End
commit

2

Kapsamlı hata ayıklamadan sonra benim için düzeltme basit bir eksik atıştı; geri dönüşten sonra catch ifadesidir. Onsuz bu çirkin hata mesajı, sonuçta elde ettiğiniz şeydir.

begin catch
    if @@trancount > 0 rollback transaction;
    throw; --allows capture of useful info when an exception happens within the transaction
end catch

2

Aynı hata mesajını aldım, hatam COMMIT TRANSACTION satırının sonunda noktalı virgül olmasıydı


Bu kadar basit. Ayrıca, SP'nin tam olarak çalıştırılmayacağı bir durumda, davamın bir 'ROLLBACK' ifadesine ihtiyacı vardı. Sadece işlemi kapatmak / bitirmek için.
J Cordero

1

Bu ifadeyi işlemimden çıkardıktan sonra bu hatayla bir kez karşılaştım.

COMMIT TRANSACTION [MyTransactionName]

1

Kanımca kabul edilen cevap çoğu durumda abartılı bir cevaptır.

Hatanın açıkça ifade ettiği gibi, hatanın nedeni genellikle BEGIN ve COMMIT arasındaki uyumsuzluktur. Bu, şunu kullanmak anlamına gelir:

Begin
  Begin
    -- your query here
  End
commit

onun yerine

Begin Transaction
  Begin
    -- your query here
  End
commit

Başladıktan sonra İşlemi ihmal etmek bu hataya neden olur!


1

Aynı prosedürde / sorguda birden fazla işleminiz olmadığından emin olun, bunlardan biri veya daha fazlası taahhüt edilmemiş durumda.

Benim durumumda, sorguda yanlışlıkla bir BEGIN TRAN ifadesi vardı


1

Bu, SP'yi C # kodunuzdan çağırma şeklinize de bağlı olabilir. SP bazı tablo türü değeri döndürürse, ExecuteStoreQuery ile SP'yi çağırın ve SP herhangi bir değer döndürmezse, SP'yi ExecuteStoreCommand ile çağırın


1

Kullanmaktan kaçın

RETURN

kullanırken ifade

BEGIN TRY
    ... 
END TRY

BEGIN CATCH
    ...
END CATCH

ve

BEGIN, COMMIT & ROLLBACK

SQL saklı yordamlardaki ifadeler


0

Aşağıdaki gibi bir kod yapısına sahipseniz:

SELECT 151
RETURN -151

Sonra kullan:

SELECT 151
ROLLBACK
RETURN -151
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.