2014-09-03 27 views
6

Haftalık olarak "serbest bıraktığım" bir veritabanına sahibim, yani bir yedek personelin başlayabileceğimi gönderiyorum ve son haftadan yükseltmek için kullanabilecekleri bir güncelleme komut dosyası yayınlıyorum (böylece mümkün olduğunca güncel verilerini saklayabilirler)). Bu senaryo elbette çok sayıda DDL - CREATE TABLE, ALTER TABLE ve benzerlerini içerir. Bunun temel yapısı şu şekildedir:SQL Server'da CREATE TABLE ifadeleri ROLLBACK'e bağışık mı?

/* 

HOW TO USE THIS SCRIPT 

1. Run it against your existing DB 
2. Check whether there were any errors 
3. If there were, issue a rollback by highlighting this: 
     ROLLBACK 
    and executing it 
4. If there weren't, issue a commit by highlighting this: 
     COMMIT 
    and executing it 
5. !!! Not doing either of these will leave a transaction open, which will 
    probably cause all further queries to time out till you do !!! 

*/ 

SET XACT_ABORT ON; 
SET TRANSACTION ISOLATION LEVEL SERIALIZABLE; 

BEGIN TRANSACTION; 
GO 

-- Boilerplate checking and whatnot goes here 
GO 

-- Guts of operation, part 1 
GO 

-- Guts of operation, part 2 
GO 

-- Guts of operation, part 3 
GO 

-- . . . 
GO 

-- Guts of operation, part N 
GO 

-- Boilerplate cleanup stuff here 
GO 

Ben açık işlem bıraktı ve, elle bitirme ne bağlı başa onlara dikkat edeceğiz. Bunun otomatik olmasını isterdim, ama her şeyin her zaman uzun bir seri halinde birkaç seri olduğunu ve TRY blokların elbette partileri yaymayacağını düşünürdüm. Böylece acıyı hafifletmek için son zamanlarda SET XACT_ABORT ON; eklenmiştir. Ne olursa olsun, kendimi onsuz beri denedim ve senaryo için hiçbir fark yaratmıyor. Neyse.

Son zamanlarda, bu komut dosyalarından biri, varolan tablolara denetim kısıtlamaları eklemek için tablolar ve diğer ifadeler oluşturma ifadelerine sahipti. Kullanıcılarımdan biri komut dosyasını çalıştırdı ve kısıtlama üzerinde bir hataya çarptı; Kısıtlamayı ihlal eden önceden varolan verileri vardı. Tamam, sorun değil, bir ROLLBACK yapın. Doğru, bir tane yapmasına gerek yoktu, XACT_ABORT zaten yaptı. Git ve veri satırlarını düzelt ... bitti. Şimdi tekrar denemek için! Uhp… ne? Bu sefer kısıtlama yok, ancak tabloların zaten mevcut olduğunu söyleyen CREATE TABLE ifadelerinde hata çıkıyor! Ha? Geri dönmedi mi?

Bir yedeklemeden geri yükleme ve verileri yeniden düzeltme ve yeniden çalıştırma işlemini bitirdik. Ama bu ne burada ne de orada değil.

Öyleyse, sevgili okuyucular: Bu tabloların oluşturulması işlemin geri dönüşünden nasıl kurtuldu? Onlara yapmamalarını nasıl sağlayabilirim?


DÜZENLEME: Tamam, burada çalıştırabilirsiniz bir örnek.

USE tempdb; 
GO 

CREATE DATABASE example; 
GO 

USE example; 
GO 

CREATE TABLE foo (a INT); 
GO 

INSERT INTO foo 
VALUES (100); 
GO 

SET TRANSACTION ISOLATION LEVEL SERIALIZABLE; 

BEGIN TRANSACTION; 
GO 

ALTER TABLE foo ADD CHECK (a < 10);-- Gives error "The ALTER TABLE statement conflicted with the CHECK constraint…", as expected 
GO 

CREATE TABLE bar (b INT); 
GO 

ROLLBACK;-- Gives error "The ROLLBACK TRANSACTION request has no corresponding BEGIN TRANSACTION." Huh? Where did our transaction go? 
GO 

SELECT * 
FROM bar;-- Gives no error. Table still exists! NOT expected! 
GO 

USE tempdb; 
GO 

DROP DATABASE example; 
+0

Hayır. Geri bildirime karşı bağışık değiller, açıklamanızdan durumunuzda ne olduğunu bilmek zor. –

+0

Sorunu yeniden oluşturabileceğiniz en basit yolu bulmaya çalışın. Bu, problemi analiz etmemize yardımcı olur. – Andomar

cevap

5
SQL Server talihsiz bir hata işleme davranışına sahiptir. Belirli bir hatayı bağlı olarak bazen deyimi, toplu iş, işlem ve bağlantıyı veya bazılarını veya hiçbirini iptal eder. Bu, karşı programlamak için çok hata eğilimli bir modeldir.

Sizin durumunuzda, toplu iş ve işlem, XACT_ABORT nedeniyle iptal edildi. Ancak GO toplu ayırıcıdır. Birden çok parti var. Daha sonraki partiler çalışmaya devam eder.

Bir toplu iş kullanın veya önceki partilerin işleyip işlemediğini kontrol edin (belki @@TRANCOUNT'u kontrol ederek).

(SQL Server için daha iyi bir model, işlemi geri almak, ancak açık tutmak ve gelecekteki tüm ifadelerin başarısız olmasını sağlamak için daha iyi bir model olacaktır. Bu, komut dosyasının geri kalanını işlemin içinde bırakacak ve hiçbir şeyin sızmasına izin vermeyecektir. Böyle bir özellik var.)

+1

Ah, böyle oldu! SQLcmd modu ve ': hata çıkışında 'yardımcı olabilir. –

+0

Hmm, Tek bir toplu işten kaçamıyorum çünkü henüz varolmayan nesnelerde sözdizimi denetimi yapmıyor. Örneğin, bir "CREATE TABLE" ile sonuç tablosunu içeren bir şey yapan veya başka bir şekilde yürütme girişiminde bulunmayacak bir şey arasında "GO" yapmak zorundayım.Ve SQLCmd modunu kullanıcılara açıklamak için çok az şeyim var…:/ – Atario

+0

@Atario Ayrıca, her şeyi denemeye başlayabilirsiniz ... yakalama ve ardından bağlantı iptal etme hatası veya catch bloğundaki "noexec açık" ayarı. –

İlgili konular