Skip Navigation LinksAnasayfa > Etiketler
Sql Server'da TRANSACTION ve WITH (NOLOCK) kullanımı Adı ne olursa olsun tüm RDBMS (relational database management system) veritabanları locking kavramını içinde barındırır. Veritabanında bir kayıt üzerinde işlem yapılırken veritabanı motoru o kaydı kilitler ve işlem tamamlanana kadar değişiklik yapılmasına izin vermez. Dolayısıyla aynı kayda erişmeye veya güncellemeye çalışan diğer kullanıcılar kayıt serbest bırakılana kadar beklemek zorundadır. Bu handikap küçük ve nispeten orta ölçekli projelerde çok fazla hissedilmezken, anlık milyonlarca işlemin yapıldığı transaction kullanılan büyük projelerde ciddi olarak hissedilmektedir.

WITH (NOLOCK) terimi bir Microsoft Sql Server kilitleme ipucudur.

Veritabanımızda Stock adında bir tablomuzun olduğunu varsayalım.
Bu tablo, üzerinde yoğunluklu işlem yapılan bir tablo olsun.

SELECT StockID, StockItem, StockStatus FROM dbo.Stock WITH (NOLOCK)


ifadesi Stock tablosunda kilit oluşturmadan kayıt getirmeye yarar. Böylece bu tabloya başka kullanıcılar tarafından eş zamanlı yapılan insert, delete, update işlemleri select sorgusunun yarattığı kilit beklenmeksizin gerçekleştirilir. Bu bir avantaj olmakla birlikte bu yöntemin ciddi dezavantajları da bulunmaktadır. Yanlış locking uygulamaları "READ UNCOMMITTED (Dirty Read)" oluşmasına neden olabilmektedir.

Bu durumu basit bir örnekle açıklamak gerekirse; FB-GS maçına sadece 1 biletin kaldığını varsayalım.

Ahmet, Mehmet, Anıl, Kemal, Selim kullanıcıları firmanın web sitesi veya yazılımı üzerinden aynı anda sipariş verdiler. Ahmet ile Mehmet'in işlemi aynı atomik zamanda gerçekleşti. Ahmet'in işlemi gerçekleşti ve kayıt sayısı sıfıra düşürüldü. Ahmet'in işlemi WITH (NOLOCK) ile gerçekleştirildiği için Mehmet de aynı anda kayıda erişebildi ve bir update işlemi yapmaya çalıştı. Bu durumda uygulama da mantık hatası oluştu ve sistem hata verdi. Bu örnekte hataya WITH (NOLOCK) teriminin yanlış kullanımı neden olmuştur fakat aynı örnekte (WITH NOLOCK) kullanılmaması da oluşacak hatayı engellemez. Hatayı ortadan kaldıracak tek çözüm TRANSACTION kullanmaktır.

Örnekte gerçekleşmesi gereken işlemler ve stored procedure kodu şöyle olmalıdır:

1- Sistemde istenilen bilet sayısı kadar bilet var mı?
2- Bilet varsa Transaction başlat.
3- Ödemeyi al, bilet kotasını azalt.
4- Ödeme başarılıysa transaction'ı tamamla, aksi halde kotayı eski durumuna getir.
5- Bilet yoksa işlemi reddet.

Yazdıklarımızı koda dökecek olursak :

ALTER PROCEDURE [dbo].[TicketSales]
(
@TicketNumber bigint, -- talep edilen bilet
@GameID bigint, -- maç id
@UserID bigint, -- kullanıcı id
@CompanyID bigint -- satıcı firma id
)
AS
BEGIN
DECLARE @result tinyint
DECLARE @TicketQuota int
DECLARE @TicketFee money
SET @TicketQuota = 0 -- varsayılan kota sıfırdır.

SELECT @TicketQuota = TicketQuota, @TicketFee = TicketFee FROM Tickets WHERE GameID=@GameID

-- yeterli kota varsa
IF @TicketNumber>=@TicketQuota
BEGIN

BEGIN TRANSACTION
-- Ödemeyi al. Kullanıcı hesabından eksilt.
UPDATE Accounts SET AccountAmount = AccountAmount - (@TicketFee * @TicketNumber) WHERE AccountHolderId = @UserID

-- Firma hesabına aktar.
UPDATE Accounts SET AccountAmount = AccountAmount + (@TicketFee * @TicketNumber) WHERE AccountHolderId = @CompanyID

-- kotayı azalt
UPDATE Tickets SET TicketQuota = TicketQuota - @TicketNumber WHERE GameID=@GameID

IF @@ERROR=0
BEGIN
-- tüm işlemleri onayla.
COMMIT TRANSACTION
SET @result=0 -- işlem tamam. İyi seyirler. :)
END
ELSE
BEGIN
-- tüm işlemleri geri al. Tüm değişiklikler geri alınır.
ROLLBACK TRANSACTION
SET @result=1 -- işlem başarısız. ödeme başarısız, sistem hatası vs... :(
END
END
ELSE
BEGIN
SET @result=2 -- yeterli bilet yok. :(
END
RETURN @result

END


Yukarıdaki prosedürün oldukça anlaşılır olduğunu düşündüğüm için detaylarını tek tek açıklamıyorum. İçinde transaction'ın nasıl başlatıldığını, hangi şartlarda işlemlerin onaylandığını ve hangilerinde geri alındığını incelemenizi öneriyorum.

Transaction konusu çok ayrıntılı olarak incelenmesi gereken bir konu olduğu için başka bir yazıda detaylarından bahsedeğim. Biz burada veritabanının yerleşik olarak sunduğu transaction yapısından faydalandık. Kurumsal projelerde genelde sadece bu iş için ayrılmış bir Transaction sunucusu bulunmaktadır. Diğer yandan ADO.NET de içinde barındırdığı tümleşik transaction desteği ile bize uygulama tarafından transaction oluşturma ve yönetme şansı verir.

Ben transaction'ların veritabanı motoru tarafından oluşturulmasını tercih edenlerdenim. Seçim size kalmış.

"Bug Free" kalın.

Eklenme Zamanı6/26/2007 3:38 AM   Yorum EkleYorumlar (4)   EtiketlerEtiketler : locking , nolock , sql , stored procedure , transaction