Saklı Yordam için işlem kullanma


18

Birkaç komut çalıştıran bir saklı yordam var. Bu komutların saklı yordamın işleminde sarılmasını istemiyorum. 4. komut başarısız olursa, 1., 2. ve 3. olanların geri kalmasını değil geri kalmasını istiyorum.

Saklı yordamı, büyük bir işlem olarak yürütülmeyecek şekilde yazmak mümkün mü?

Yanıtlar:


16

Tüm işlemler tek bir işlemde gerçekleştirilmez. Bu örneğe bir göz atın:

use TestDB;
go

if exists (select 1 from sys.tables where object_id = object_id('dbo.TestTranTable1'))
    drop table dbo.TestTranTable1;
create table dbo.TestTranTable1
(
    id int identity(1, 1) not null,
    some_int int not null
        default 1
);
go

insert into dbo.TestTranTable1
default values;
go 4

select *
from dbo.TestTranTable1;

if exists (select 1 from sys.sql_modules where object_id = object_id('dbo.ChangeValues'))
begin
    drop proc dbo.ChangeValues;
end
go
create proc dbo.ChangeValues
as
    update dbo.TestTranTable1
    set some_int = 11
    where id = 1;

    update dbo.TestTranTable1
    set some_int = 12
    where id = 2;

    update dbo.TestTranTable1
    set some_int = 13
    where id = 3;

    -- this will error out (arithmetic overflow)
    update dbo.TestTranTable1
    set some_int = 2147483648
    where id = 4;
go

exec dbo.ChangeValues;

select *
from dbo.TestTranTable1;

İşte çıktı:

resim açıklamasını buraya girin

sql_transactionEtkinliği izlemek için bir Genişletilmiş Etkinlikler oturumu oluşturarak , yürütme işleminin çıktısı şöyledir dbo.ChangeValues:

resim açıklamasını buraya girin

Yukarıdaki ekran görüntüsünde de görebileceğiniz gibi, dört ifadenin her biri için ayrı işlemler vardır. İlk 3 taahhüt ve sonuncusu hata nedeniyle geri çekilir.


16

Bence bir parti ve bir işlem hakkında kafa karışıklığı olabilir .

Bir işlem ya başarılı ya da birim olarak başarısız olur tabloların bir deyim veya kümesidir. Tüm DDL ifadeleri işlemlerin kendisindedir (örneğin, 100 satırı güncellerseniz ancak satır 98 bir hata atarsa, satırların hiçbiri güncellenmez). Bir işlemi bir dizi ifadeye BEGIN TRANSACTIONve ardından ya COMMITda tuşlarını kullanarak da sarabilirsiniz ROLLBACK.

Bir yığın birlikte yürütülen bir ifade dizisidir. Saklı yordam bir parti örneğidir. Saklı yordamda, bir deyim başarısız olursa ve hata yakalama (normalde TRY/CATCHbloklar) varsa, sonraki deyimler yürütülmez.

Saklanan proc kendisi veya bir dış kapsam (bu yordamı çağıran uygulama veya depolanan proc gibi) içinde hata hata olduğundan, bir hata oluştuğunda toplu iş iptal ediliyor olduğundan şüpheleniyorum. Bu durumda, hataları yakalayan herhangi bir kapsamda hataları nasıl ele alacağınızı ayarlamanız gerektiğinden, bu çözülmesi daha zordur.


"Mağaza prosedürü bir parti örneği" diyen bir makale bulamadım. Saklı Yordam toplu iş çok benzer inanıyorum ama bir Toplu değil. Temel fark şudur: SP, Yığınlardan farklı olarak birkaç kez çalıştırılmaya hazırdır ve çalıştırılmaya hazırdır. Benzerlikler şunlardır: - İkisi de her bir komutu aynı anda yürütür. - Bir komut başarısız olursa, önceki tüm komutlar uygulanır (bir işlemde çalışmadığı sürece) - bir komut başarısız olursa, sonraki tüm komutlar yürütülmez.
Ashi

6

Sql sunucusundaki her şey bir işlemde bulunur.

Açıkça belirttiğinizde begin transactionve end transactionsonra Açık İşlem olarak adlandırılır . Yapmadığınızda , Örtük işlemdir .

Hangi modda olduğunuzu değiştirmek için şunu kullanırsınız:

set implicit_transactions on

veya

set implicit_transactions off

select @@OPTIONS & 2

yukarıdaki 2 değerini döndürürse, örtülü işlem modundasınız demektir. Eğer 0 döndürürse, otomatik taahhütte bulunursunuz.

Bir işlem TÜM veya hiçbir şey veritabanı tutarlı bir durumda tutmak .. ACID özelliklerini hatırlıyorum.

CREATE TABLE [dbo].[Products](
    [ProductID] [int] NOT NULL,
    [ProductName] [varchar](25) NULL,
    [DatabaseName] [sysname] NOT NULL,
 CONSTRAINT [pk_Product_ID_ServerName] PRIMARY KEY CLUSTERED 
(
    [ProductID] ASC,
    [DatabaseName] ASC
)WITH (PAD_INDEX  = OFF, STATISTICS_NORECOMPUTE  = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS  = ON, ALLOW_PAGE_LOCKS  = ON) ON [PRIMARY]
) ON [PRIMARY]

GO


-- insert some data 
INSERT INTO [dbo].[Products]([ProductID], [ProductName], [DatabaseName])
SELECT 1, N'repl1_product1', N'repl1' UNION ALL
SELECT 1, N'repl2_product1_02', N'repl2' UNION ALL
SELECT 1, N'repl3_product1_03', N'repl3' UNION ALL
SELECT 2, N'repl1_product1_01', N'repl1' UNION ALL
SELECT 2, N'repl2_product1', N'repl2' UNION ALL
SELECT 2, N'repl3_product1_03', N'repl3' UNION ALL
SELECT 3, N'repl1_product1_01', N'repl1' UNION ALL
SELECT 3, N'repl2_product1_02', N'repl2' UNION ALL
SELECT 3, N'repl3_product1', N'repl3' UNION ALL
SELECT 4, N'repl1_product1_01', N'repl1' UNION ALL
SELECT 4, N'repl2_product1_02', N'repl2' UNION ALL
SELECT 5, N'repl1_product1_01', N'repl1' UNION ALL
SELECT 5, N'repl2_product1_02', N'repl2'

- SP'yi şimdi oluşturun - ilk 3'ün başarılı olacağını ve dördüncü dizenin kırpılması nedeniyle başarısız olacağını unutmayın ...

IF OBJECT_ID ('usp_UpdateProducts', 'P') IS NOT NULL
    DROP PROCEDURE usp_UpdateProducts;
GO
create procedure usp_UpdateProducts
as 
begin try
update Products 
set ProductName = 'repl1_product1'
where DatabaseName = 'repl1'and ProductID = 1;
update Products
set ProductName = 'repl2_product1'
where DatabaseName = 'repl2' and ProductID = 2;
update Products
set ProductName = 'repl3_product1'
where DatabaseName = 'repl3' and ProductID = 3;
update Products
set ProductName = 'repl3_product1_03&&&&&&&&&&39399338492w9924389234923482' -- this will fail ...
where DatabaseName = 'repl3' and ProductID = 4;
SELECT 1/0;
end try
begin catch
SELECT 
        ERROR_NUMBER() AS ErrorNumber,
        ERROR_SEVERITY() AS ErrorSeverity,
        ERROR_STATE() as ErrorState,
        ERROR_PROCEDURE() as ErrorProcedure,
        ERROR_LINE() as ErrorLine,
        ERROR_MESSAGE() as ErrorMessage;
end catch
go

Bakınız: Her zaman bir işlem oluşturmak kötü bir uygulama mıdır?


3

Saklı yordamlar varsayılan olarak bu şekilde çalışır. Saklı yordam bir işlemin içine otomatik olarak sarılmaz.

Saklı yordamın ilk hataya ulaştığında durmasını istiyorsanız, örneğin komut 2 ile ilgili bir sorun olması durumunda geri dönmek için bazı TRY / CATCH girişleri koymak isteyeceksiniz.


2

Her komut için ayrı işlemlere ihtiyacınız olacaktır. Bunu kaydedilmiş işlemlerle de yapabilirsiniz:

SAVE TRANSACTION (Transact-SQL)Ürün belgelerine bakın .

Tek tek işlemler saklı yordamlar için varsayılan davranış olduğunu nitelendirmek istiyorum, çünkü tüm ifadeler örtülü işlemlere sarılmış; ancak, hiç kimse kodunun kaderini kontrol etmek için örtük işlemlere güvenmemelidir. İşlemlerin üretim kodunda nasıl ele alınacağını açıkça kontrol etmek çok daha iyi bir uygulamadır.


-2

parçaların her birini bir BEGIN TRAN ile ayırın ve işlemin başarılı olup olmadığını kontrol edin. taahhüt edildiğinde, aksi takdirde bir geri alma yapın, çünkü hepsi aynı seviyeden yürütüldüğünden, başarısız olursa hepsini geri almak zorunda kalmadan her bölümü ayrı ayrı işleyebileceksiniz.

Daha fazla bilgi için http://msdn.microsoft.com/en-us/library/ms188929.aspx adresine göz atabilirsiniz.


1
Bu, Saklı Yordamım içinde alt işlemler yaratacak mı? İdeal olarak bunu önlemek istiyorum
Matthew Steeples

1
SP bir işlem içinden çağrılırsa, yukarıdaki kaydedilmiş işlemler yanıttır. Sp ile çağrılmazsa, mrdenny doğrudur. Sql sunucusu iç içe geçmiş işlemi desteklemiyor.
StrayCatDBA

@StrayCatDBA sadece açıklığa kavuşturmak için .. SQL Server'da Yuvalanmış İşlemler var, ama onlar kötü .. SQL Server, iç içe işlemler denilen diğer işlemler içinde işlemlere başlamanızı sağlar. Sqlskills.com/blogs/paul/… , msdn.microsoft.com/en-us/library/ms189336(v=sql.105).aspx ve sqlblog.com/blogs/kalen_delaney/archive/2007/08/13
Kin Shah

2
Açık olmak gerekirse (ve bağlantıları tıklamak istemeyen tembeller için) aslında başka bir işlem başlatmıyorsunuz. Aka, Paul'ün gönderisindeki başlık: "Efsane: İç İçe İşlemler gerçek." Bunlar gerçek işlemler değil. Yuvalanmış bir işlemdeki COMMIT, @@ TRANCOUNT değerinde azalma dışında hiçbir şey yapmaz. BEGIN TRAN / COMMIT'i iç içe yerleştirirseniz bir hata almamanız doğrudur, ancak bu gerçek iç içe geçmiş işlemlere sahip olmaktan farklıdır.
StrayCatDBA
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.