.NET Framework / COM+ Öğrenelim - 5
Transactionlar veri bütünlüğünün ve işlemin kesinliğinin garanti altına alındığı önemli yapılardır. Bir kaynak veya birden fazla kaynak üzerinden birbirinden bağımsız birçok işlem yapıldığı durumda bu işlemlerin herhangi birinde bir hata oluşması veya o işlemin yapılamama durumunun ortaya çıkması halinde tüm işlemlerin geri alınarak verilerin işlem başlanmadan önceki haline dönmesi hayati önem taşımaktadır. Transactionlara birçok programda ihtiyaç duyulmaktadır. Transactionlar konusunda konuyu pekiştirmek amacıyla en sık verilen örnek banka hesapları arasındaki para transferlerinin yönetilmesidir. Burada bir hesaptan para çekildiği zaman diğer hesaba başarı ile yatması garanti edilmelidir, işte bu noktada transaction devreye girer ve çekilen paranın hesaba yatamaması durumunda tüm işlemi geri alarak bakiyeyi ilk durumuna geri getirecektir.
Transaction’lar ACID adı verilen temel özellikleri taşımalılardır. ACID’in açılımını inceleyecek olursak;
Atomicity : Bu özellik transactionda bulunan tüm işlemlerin başarılı bir şekilde yapılmasını veya hehangi bir hata oluştuğu zaman tüm işlemlerin geri alınması temelinin barındığı özelliktir. Bu tarz bir kodun yazılım geliştirici tarafından yazılmasının çok zamana malolacağı ve yazılım maliyetlerini arttıracağı transactionların bizim için ne kadar önemli oldğunu ortaya koymaktadır.
Consistency : Bu özellik ise veri tutarlılığının ve bütünlüğünün garanti altına alınmasını sağlamaktadır. Bu konun başında verdiğimiz banka örneğindeki işlemlerin transactionlarla yönetildiğini düşünürsek yeni para yatırılmadığı ve sadece hesaplar arası para transferi yapıldığı bir sistemde tüm hesaplardaki toplam tutar hiçbir zaman değişmeyecektir.
Isolation : Aynı kaynak üzerinde eşzamanlı yapılabilecek işlemlerden oluşabilecek hataların engellemesini temel alan özelliktir. İki tane transactional işlemimiz olduğunu yine banka örneği üzerinde inceleyelim. Aynı anda başlayan işlemlerden ilki bir hesaptan parayı çekti ancak diğer hesaba parayı yatıramadı, tam bu sırada ikinci işlem devreye girerek hesapta kalan parayı okudu. İlk işlem işlemi geri aldıktan sonar ikinci işlemde görülen hesap bakiyesi yanlıştır. Çünkü bu değişiklik birinci işlemin yeraldığı transaction içinde rollback edilmiştir. İşte bu gibi durumların önüne geçmek amacıyla isolation kullanılır ve bir lock level belirlenerek ikinci transactionun devreye bile girmemesini sağlamak elimizdedir.
Durability : Üzerinde işlem yapılan serverda herhangi bir yazılım veya donanım problemi olması durumunda transactionlar kendisini ilk başladığı duruma getirebilecek özelliktedirler.
Bir Resource Manager(Kaynak Yöneticisi) veriyi saklamaktan sorumlu olan ve transaction destekleyen yapılardır. Desteklenen transactionlar local veya distributed olabilirler. En çok kullanılan resource manager Microsoft SQL Server 7.0’dır. .NET te bulunan transactionlar sadece resource manager’lar ile çalışmayı desteklemektedir. Eğer verilerinizi bir file system üzerinde tutuyorsanız bu durumda verileriniz distributed bir transaction içinde yeralmasını sağlamak için Compensanting Resource Manager gibi teknolojileri kullanabilirsiniz. Biraz once değindiğimiz local ve distributed transaction kavramlarını inceleyelim.
Local Transactions : Bu tür transactionlar client server uygulamalarında ve değişikliklerin bir connection üzerinden bir kaynağa yapıldığı durumlarda gerçekleşir. ADO.Net bu transaction sistemini desteklerdekn distributed transactionlara .Net Enterprise Services destek vermektedir.
Local transactionların çalışması için ilk once transactionu yaratmalısınız ve işlemleri gerçekleştirmeye başladıktan sonar oluşan herhangi bir hatada transaction üzerinde rollback komutunu yollamak suretiyle işlemleri geri alabilir veya işlemleriniz hatasız tamamlanmışsa commit komutunu yollamak suretiyle onay bekliyen değişikliklerin hepsini onaylayarak transactionun başarılı bir şekikde sonlanmasını sağlayabilirsiniz.Bu noktadan sonar kaynağa bağlanan diğer kullanıcılar değişiklikleri görebililecektir. Local transactionlari yaratmak için iki yol mevcuttur bunlardan biri T-Sql ile yaratılan stored procedure lerin içine transaction yazarak, bir diğeri ise ADO.Net veya OLEDB ile transactionları yönetmektir.
Distributed Transactions : Local transactionlar bir resource üzerine bir connection ile erişildiğinde gerçekleşmesine karşın Distributed transactionlar ise birden fazla kaynağa erişebilirler ve bunların herbirinin kendine ait transactionları merkezi bir yerden basit bir mantıkla işleyen transaction tarafından yönetilmelidir. İşte bu yönetim işleminden COM+ uygulamalarında Distributed Transaction Coordinator (DTC) bulunmaktadır. DTC windows xp ile beraber gelen bir yapıdır.
DTC nin transactionları yönetebilmesinin mantığı her kaynağın bulunduğu makinada çalışan DTC’lerin birbirleriyle haberşleşebilmesidir. Bu durumda distributed transactionların farklı sistemler üzerinde çalışacağından bir şekilde herbirinin identify edilmesi gerekmektedir, DTC ise bu konuda her transactiona unique Unit Of Work Id adı verilen bir GUID atar. Bir transactionun GUID’ini almak için ContextUtil objesinin Transaction propertysini kullanabilirsiniz.
DTC distributed bir transaction yarattıktan ve Unit Of Work Id atadıktan sonra resource manager lara yapılacak connectionlar transaction içinde yer almalıdır ve DTC bunu bize otomatik olarak sağlar. Ancak Açık connectionlarıyla beraber Nesne havuzuna alınmış objeler için transactionlar elle yazılmak zorundadır, bunun sebebi ise connection açıldığı sırada herhangi bir transaction belirtilemiyor olmasıdır.
DTC’nin mantığında Coordinator’un diğer kaynaklardaki DTC lerle haberleşerek transactionlar yaratmak olduğundan bahsetmiştik Şimdi ise .Net Enterprise Services’in bize sunduğu transactionları inceleyelim.
.Net Enterprise Services’in bize sunduğu özelliklerden en güzeli belkide bir nesneyi transaction içinde yer almasını sağlamak için extradan birçok kod yazmamıza gerek bırakmamasıdır. Siz sadece yazmış olduğunuz bileşenin transaction içinde nasıl yer alacağına karar verirsiniz, eğer bileşeniniz transactiona gerek duyuyorsa .Net Enterprise Services DTC’yi ve COM+’ı kullanarak otomatik olarak bir distributed transaction yaratacaktır.
Yarattığımız bileşenlein transaction özelliğini transaction özelliğini kullanarak sadece bileşen düzeyinde belirleyebiliriz. Bu özellik bize TransactionAttribute classı ile beraber gelen bir özelliktir. Bir transaction için beş farklı özellik belirlenebilir. Şimdi ise bunları inceleyelim.
Disabled : Transaction desteklenemez. Bu özelliğin atandığı nesneler çağırılırken transaction talebinde bulunulursa COM+ bunu reddedecektir.
Not Supported : Transactionlar desteklenemez. Herhangi bir özellik belirtilmediğinde bu özellik default olarak kullanılacaktır. COM+ bileşenin transaction içinde yer alamaycağını garantiler. Yani eğer transaction isteği varsa yeni bir context açılır ve bileşen bu context içinde çalışır.
Supported : Transactionlar desteklenir. Eğer istemcinin context’inde transaction varsa nesne transaction içinde yer alır ancak transaction yoksa nesne transaction içinde yer alamacan çalışabilir.
Required : Bu özellikte ise transactionlar desteklenmektedir ve nesnenin çalışması için gereklidir. Eğer istemcinin context’inde transaction varsa bileşen aynı transaction içinde çalışır ancak yoksa bileşen kendisi için bir gtransaction yaratacaktır.
Requires New : Transactionlar desteklenmektedir. COM+ nesne her yaratıldığında yeni bir transaction yaratacaktır.
Şimdi bu özellikleri bileşenimize kodla ve Component Services Administrative Tool’u kullanarak nasıl atayacağımızı inceleyelim.
Public Class Bilesenim
Public Sub Methodum()
Ayrıca Services Administrative Tool’da bulunan bileşenin üzerine sağ tuşla tıklanıp Properties penceresi açıldıktan sonra transaction tab’ı seçilir ve buradan gerekli ayarlar yapılabilir. Ancak unutulmaması gerekn uygulamanın durdurulup tekrar başlatılması gerekmesidir.
Transaction içinde yeralan bir nesnenin bir sonraki transactiona başlanmadan önce yok edilmesi gerekliliğini isolation konusunda incelemiştik. Şimdi bunu nasıl yapacağımızı inceleyelim. Bu konuda endişelenmeye gerek yoktur bunu bizim için JIT Activation yapacaktır. Ancak burada dikkat etmemiz gerek kural transactionumuzun özelliğinin Supported, Required veya Requires New Şekilde ayarlanmış olması halinde Just In Tıme Activation özelliğini true olarak ayarlanması gerekliliğidir.
Aynı transactionu paylaşan COM+ bileşenlerine transaction stream adı verilir ve bu yapı transactionların bir context ten diğerine geçişini sağlar. Şimdi COM+’ın bir ileşeni aktive etmesi durumunda transaction ile ilgili yaptığı işleri inceleyeleim. Bu işlem sırasında COM+ kataloğu kontrol edilir ve transaction desteği bileşen tarafından gereksiniyorsa çağıran context te aktif transaction olup olmamasına ve yaratılacak olan bileşenin transaction özelliğine bakılarak aşağıdaki işlemlerden biri yapılır.
Eğer bileşen transaction içinde yer alamayacak şekilde ayarlanmışsa yeni objenin context’ine transaction yaratılmaz.
Çağıran context içinde bulunan transaction ile bilgiler alınır.
DTC ile iletişim kurulur ve yeni bir transaction yaratılarak yeni bileşenin context’ine bir transaction yaratılır.
Bir bileşen COM+ ortamı dışında çalışan bir client tarafından veya mevcut context içinde çalışan bir COM+ bileşeni tarafından aktive edilebilmektedir.
Transaction içinde yeralan ilk bileşene transaction root bileşeni adı verilir. Bu bileşeni yaratan client’a ise root client ismi verilir. Root Client trafından yaratılan istek root client a geri dödüğü anda işlem transaction stream dışına çıkmış olacaktır.
Transactionlar Nasıl Çalışır
Distributed transactionlarda commit veya rollback komutlarını desteklemelidirler. Bu durumda distribted transactionların commit veya rollback olmasını COM+ yönetir. Bu yönetim işlemini her bileşen için bir dizi bit değişken kullanarak ve bu değişkenlerin değerlerini analiz ederek yönetmektedir. Kullanılan bu bit değişkenler aşağıda açıklanmıştır.
Done Bit : Her Context’te bulunmaktadır. COM+ transaction özelliği required olarak ayarlanmış tüm bileşenlerde JIT Activation için ayarlanmış olmalı ve farklı Contextlerde çalışabilmelidir. Bileşen aktive olduğunda Done Bit’inin değeri false olurken bileşenin işi bittiğinde ve deaktive olduğunda bu bit değişkenin değeri true olmalıdır.
Consistent Bit : Her bir bileşende bulunan bu değişken o bileşende yapılan işlemlemlerin bir bütünlük sağlayıp sağlamadığı tutulur. Yani bir transaction içinde yeralmış tüm consistent bitlerin değeri true olduğunda transaction commit edilirken aksi durumda transaction rollback edilecektir.Bir bileşen aktive edildiğinde bu bileşen varsayılan olarak true gelmektedir.
Abort Bit : Consistent Bit’in zıtti gibi düşünebileceğimiz bu bit değişken transaction bazındadır. True olduğunda transaction rollback edilmelidir. Yeni bir transaction başladığı anda oluşturulur ve varsayılan değeri varsayılan olarak false gelmektedir. Bit’in değeri True olduktan sonra değiştirilemeyecek şekilde oluşturulmuştur.
Client Yönetimli Transactionlar
.Net Enterprise Services’in bileşenlere otomatik olarak transaction servisi sağlamasına rağmen bazı durumlarda root client’in transactionları manual olarak yönetmesi gerekebilir. Örneğin ServicedComponent classından türememiş managed bir bileşenin diğer servis verilen bileşenleri yönetmesinin istendiği durumlarda bu bileşenin transaction yaratabilir ve yönetebilir şekilde oluşturulmuş olması gerekemktedir. Bunun gibi extrem durumlar için COM+ içinde TransactionContext COM classını barındıran bir COM kütüphanesi sunar. Bize sunulan bu class’ı kullanarak COM+ distributed transactionları yaratabilir ve yönetebiliriz. Ancak bu classı kullanabilmek için projemize referans olarak COM+ Services Type Library’i eklemiş olmamız ve transaction başlatabilmek için TransactionContext classının bir instance’sini almak gerekmektedir. Ancak önemli bir nokta transactionun başlangıçını, bitişini veya abortunu sağlayan metod çağırımlarını COM+ yönetemdiğinden manual olarak koda yazılması gerekliliğidir.
TransactionContext classında kullanılabilir 3 metod vardır. Bunlar CreateInstance, Abort ve Commit’tir. CreateInstance metodu ile transaction içinde yeralacak servis verilen bileşenleri yaratabilirsiniz. İşiniz bittiği zaman commit metodunu, herhangi bir hata durumunda veya transactionu iptal etmeniz gereken durumlarda ise Abort metodunu kullanabilirisiniz. Şimdi bu kullanıma ait bir örneği inceleyelim.
Public Class ClientYonetimliTransaction
Dim tran As New TransactionContext
Dim transactionalBilesen1 As Classim1()
Dim transactionalBilesen2 As Classim2()
transactionalBilesen1 = tran.CreateInstance("COMPlus.Classim1")
transactionalBilesen2 = tran.CreateInstance("COMPlus.Classim2")
Transactionlar kullandıkları kaynakları (örn. Database kayıtları) kullandıkları süre boyunca kilitli tutarlar. Bu kilit transaction Abort veya Commit oluncaya kadar kalacaktır. Bu noktada bir transactionun bekleme süresinin çok uzaması veya farklı transactionların birbirlerini deadlock’a sokmaları durumunda transactionlar sonsuz bir süre zarfınca bekleyecekler ve bu kaynakların hiçbir uygulamaya cevap vermez hale gelmesine sebep olacaklardır. Bunu engellemek için transactionlara belirli bir timeout süresi konulabilir. Bu timeout süresini DTC yönetebilmektedir. Bu ayarlama Component Services Administrative Tool aracılığıyla yapılabilmekte veya bileşenimize kod ile ekleyebileceğimiz bir özellik olabilmektedir. İki traftanda ayarlama yapılmış ise kodda yazdığımız değerler daha baskın olacaktır..
Component Services Administrative Tool kullanarak transaction timout süresini ayarlamak için Component Services nodu genişletildikten sonra Computers klsörünün altındaki MyComputer’e sağ tıklanır ve Properties penceresi açıldıktan sonra Options sekmesi seçilerek Transaction Timeout ayarlaması rahatlıkla yapılabilir
Şimdi ise bu ayar bileşenimize kod ile nasıl ekleyeceğimize bakalım.
<Transaction(TransactionOption.Required, Timeout:=120)> _
Public Class TransactionTimeOut
Bunun yanısıra Component Services Administrative Tool aracılığıyla herbir bileşen için timeout süresi ayarlamak mümkündür. Bunu yapmak için bileşene sağ tıklayarak açılan properties penceresinde Transactions sekmesinde bulunan Override Global Transaction Timeout Value checkboxı işaretlenmeli ve Transaction Timeout süresi girilmelidir.