4.3. Hareketler

Hareketler tüm veritabanı sistemlerinin en temel konularından biridir. Bir hareketin başlıca özelliği ya hep ya hiç şeklinde uygulanmak üzere çok sayıda adımın tek bir adım haline getirilmesidir. Hareketi oluşturan adımlar arasındaki işlemler onunla işbirliği yapan diğer hareketlere görünür değildir ve hareketin tamamlanmasını engelleyen bazı olumsuzluklar olduğunda hareketi oluşturan adımların hiçbiri veritabanını etkilemez.

Örneğin, bir bankanın şube hesapları (şubeler) olsun ve bu hesaplarda çeşitli müşteri hesapları (hesaplar) ve bu hesaplarda da bir miktar nakit bulunsun. Ayşe'nin hesabından 100.00 lirayı Ali'ın hesabına geçirmek istediğimizi kabul edelim. Son derece basitleştirerek, SQL komutları şöyle olurdu:

UPDATE hesaplar SET nakit = nakit - 100.00
    WHERE ad = 'Ayşe';
UPDATE şubeler SET nakit = nakit - 100.00
    WHERE ad = (SELECT şube_adı FROM hesaplar WHERE ad = 'Ayşe');
UPDATE hesaplar SET nakit = nakit + 100.00
    WHERE ad = 'Ali';
UPDATE şubeler SET nakit = nakit + 100.00
    WHERE ad = (SELECT şube_adı FROM hesaplar WHERE ad = 'Ali');

Bu komutların ayrıntılarının burada bir önemi yoktur; önemli olan bunun basit işlemler olarak değil, ayrı ayrı güncellemelerin hepsinin birden yapılmasıdır. Bankamızın memurları bu işlemlerin ya hepsinin yapılmasını ya da hiçbirinin yapılmamasını ister. Eğer Ali, Ayşe'nin hesabından yeterli miktarı alamazsa ya da Ayşe'nin hesabından gerekli miktar alındığı halde Ali'nin hesabına geçmezse sistemin hata vermesinden başka her iki müşteri de memnun olmayacaktır. Yani, eğer işlemlerden biri gerçekleşmezse bu adımların hiçbirinin veritabanını etkilemeyeceğini garantilemeliyiz. Yapılacak işlemlerin bir hareket içinde gruplanması bize bu garantiyi sağlar. Bir hareket atomik olmalıdır, denir: diğer hareketler açısından ya tüm adımların hepsi gerçekleşmeli ya da hiçbiri gerçekleşmemelidir.

Kesinlikle emin olmamız gereken bir nokta ise bir hareket başarı ile işlemi yürütmüş olsa bile, bilginin tamam olarak veritabanına geçip geçmediğidir, son anda bir sistem kaynaklı hata olsa bile. Örneğin, Ali'nin hesabından para çekmeye çalıştığımızda, o daha bankanın kapısından çıkmadan, paranın bir hata sonucu onun hesabından çekilmiş olarak gözükmemesi gibi bir şansı göze alamayız. Tam bu noktada bir veritabanı, bir hareketle ilgili tüm işlemler yapılıp kayıtlar sabit disk gibi bir saklama alanına aktarılmadan 'tamam' sonucunu göndermez.

Bir diğer önemli nokta ise çok sayıda hareket aynı anda çalışırken birbirlerinin tamamlanmamış sonuçlarını görmemesi gerektiğidir. Örneğin bir hareket tüm şubelerdeki (şubeler) hesap miktarlarını toplarken başka bir hareket Ayşe ya da Ali'nin hesabı üzerinde işlem yapamayacaktır. Kısaca bir hareket tamam benim işim bitti demeden, diğer bir hareket bir işlem başlatamayacaktır.

PostgreSQL'de bir hareket, BEGIN ve COMMIT SQL komutları ile sarmalanmış adımlardan oluşur. Bu durumda, banka işlemlerimiz aslında şöyle görünecektir:

BEGIN;
UPDATE hesaplar SET nakit = nakit - 100.00
    WHERE ad = 'Ayşe';
-- vesaire vesaire
COMMIT;

Hareketin de belli bir noktasında işlemin iptal edilmesi gerekebilir (Mesela Ayşe'nin hesabı aktarılacak miktar için yetmeyip negatife düşerse), bunun için COMMIT yerine ROLLBACK kullanabiliriz ve böyle bir durumda tüm güncellemeler iptal edilir.

PostgreSQL aslında her SQL cümlesini sanki bir hareket gerçekleştiriyormuş gibi ele alır. Bir BEGIN komutu kullanmazsanız, her cümlenin başına örtük bir BEGIN ve cümle başarılı ise sonuna da örtük bir COMMIT getirilir. Bu nedenle, BEGIN ve COMMIT komutları ile sarmalanmış cümlelere bazan hareket kümesi de dendiği olur.

Bilginize

Bazı istemci kütüphaneleri BEGIN ve COMMIT komutlarını kendiliğinden koyar, böylece istemeden hareket kümelerinin etkileriyle karşılaşırsınız. Bu bakımdan kullandığınız arayüzün belgelerine bakmayı unutmayın.

Bir hareketi içinde kayıt noktaları belirterek cümle cümle denetlemek de mümkündür. Kayıt noktaları bir hareketin belli parçalarını seçerek iptal etmeyi mümkün kılar. Bir kayıt noktasını SAVEPOINT ile tanımladıktan sonra ihtiyaç duyarsanız, ROLLBACK TO ile bu kayıt noktasına kadar olan kısmı geri sarabilirsiniz. Bir hareketin bu iki komut arasında kalan veritabanı değişiklikleri iptal edilir, fakat, bu bölümden önce yapılanlar veritabanında kalır.

Bir kayıt noktasına kadar geri sarıldıktan sonra, işlem bu noktadan devam eder, öyle ki, bu defalarca yapılabilir. Tersine, belli bir kayıt noktasına geri sarmaya artık ihtiyaç duymayacağınızdan emin olduğunuzda, onu serbest bırakabilirsiniz, böylece sistem bazı özkaynakları serbest bırakabilir. Serbest bırakmanın da, bir kayıt noktasına geri dönmenin de tanımlanmasının ardından tüm kayıt noktalarının özdevimli olarak serbest bırakılacağını unutmayın.

Bunların hepsi hareket kümesinin içinde gerçekleşir, dolayısıyla, bu işlemlerin hiçbiri diğer veritabanı oturumlarına görünür değildir. Bir hareket kümesini işleme sokulduğunda, geriye sarma işlemleri diğer oturumlara asla görünür olmazken, işleme sokulan diğer eylemler bir birim olarak diğer oturumlara görünür hale gelir.

Bankanın veritabanını hatırlarsanız, Ayşe'nin hesabından Ali'nin hesabına 100 lira aktarmıştık ama daha sonra baktığımızda, paranın Veli'nin hesabına geçmesi gerektiğini keşfetmiş olalım. Bunun için kayıt noktalarını şöyle kullanabiliriz:

BEGIN;
UPDATE hesaplar SET nakit = nakit - 100.00
    WHERE ad = 'Ayşe';
SAVEPOINT kayıt_noktası;
UPDATE hesaplar SET nakit = nakit + 100.00
    WHERE ad = 'Ali';
-- dur bakalım ... Veli'nin hesabını kullanacağız
ROLLBACK TO kayıt_noktası;
UPDATE hesaplar SET nakit = nakit + 100.00
    WHERE ad = 'Veli';
COMMIT;

Bu örnek, şüphesiz fazla basit, fakat bir hareket bloğu üzerinde kayıt noktalarınını kullanımı ile ilgili yeterince denetim var. Dahası, sistem tarafından bir hatadan dolayı çıkış istendiğinde, ROLLBACK TO bir hareket kümesinin denetimini yeniden kazanmanın tek yoludur, tamamen gerisarma yapılıp tekrar başlanabilir.