Spring Framework’de Transaction Yönetimi

Metin Alnıaçık
2 min readFeb 18, 2024

--

Birbiriyle bağlantılı birden fazla veritabanı işlemi yapılıyorken bu işlemlerin tümünü tek bir işlem olarak kabul etmeliyiz. İşlem gerçekleştiğinde iki durumla karşılaşırız.
1 — Bu işlemleri tümü başarılıysa veritabanına kayıt gerçekleşir. Buna commit denir.
2 — İşlemlerden herhangi birinde hata alınırsa tüm veritabanı işlemleri iptal edilir. Buna da rollback denir.

Bu, ya hep ya hiç yaklaşımını da transaction olarak düşünebilirsiniz. Temel amacı verinin tutarlılığını sağlamaktır.

Bir örnek verecek olursak, klasik bir örnek olacak ama transaction işlemleri için güzel bir örnek olan bankadan para transfer işlemidir. Para gönderme işlemi ne kadar tek işlem gibi görünse de arka planda iki veya daha fazla işlemden oluşur. Biz en sade haliyle iki işlem olarak düşünelim.
Birinci işlem, paranın göndericinin hesabından düşmesidir.
İkinci işlem, paranın alıcının hesabına eklenmesidir.
Diyelim ki, birinci işlem başarıyla gerçekleşti ve para göndericinin hesabından düştü. Fakat bir nedenle alıcının hesabına aktarma esnasında bir sorun yaşandı. Bu durumda, başarılı olan birinci işlemi de geri almalıyız. Eğer işlemi geri almazsak verilerde tutarsızlık oluşacaktır.

Spring Framework kullanıyorsanız, transaction yönetimini ona bırakabilirsiniz. İlgili metodun veya sınıfın üzerine @Transactional yazmamız yeterlidir.

Örnek üzerinde detaylı olarak açıklayalım.
İki kolondan (username ve amount) oluşan bir veritabanı tablosu oluşturuyoruz.
Test amaçlı iki kayıt oluşturdum.
username: metin, amount: 70000
username: yusuf, amount: 10000

Bu metoda aşağıdaki bilgilerle istek gönderildiğinde,
{ “usernameFrom”: “metin”, “usernameTo”: “yusuf”, “amount”: 1000 }
Veritabanındaki son durum aşağıdaki gibidir.
username: yusuf, amount: 11000
username: metin, amount: 69000
Herhangi bir hata oluşmadığından veriler tutarlıdır.

Aynı metoda bir aşağıdaki bilgilerle istek gönderelim.
{ “usernameFrom”: “metin”, “amount”: 1000 }
Veritabanındaki son durum aşağıdaki gibidir.
username: yusuf, amount: 10000
username: metin, amount: 69000
Alıcı bilgisi eksik olduğundan 13. satırda program kesilecektir. O satıra kadarki işlemler veritabanına kaydedilecek fakat o satırdan sonraki işlemler veritabanına kaydedilmeyecektir. Bu durumda metin kullanıcısının hesabında 1000 eksilmiş fakat yusuf kullanıcısının hesabına 1000 aktarmamış olacaktır. Bu ciddi bir sorundur ve bu durumu ortadan kaldırmak için bu iki işlemi tek bir işlem olarak görmeliyiz.

Metodun başına @Transactional anotasyonunu ekliyoruz.

Bu ufak değişiklikle beraber sorunsuz çalışan durumlar için bir farklılık olmayacaktır. Aşağıdaki hatalı sonuç dönen isteği tekrar gönderdiğimizde,
{ “usernameFrom”: “metin”, “amount”: 1000 }
Alıcı bilgisi olmadığından 14. satırda program kesilecektir. Bu satıra kadar yapılan tüm veritabanı işlemleri de geri alınacaktır. Veritabanındaki değerler, bu metoda girilmeden önceki değerleriyle aynı kalacaktır.

NOT: transactional anotasyonunun özelliklerinden olan propagation ve isolation özellikleriyle ilgili yazılar daha sonra eklenecektir.

Örneğin tamamına github adresimden ulaşabilirsiniz.

İyi günler,
Bol kodlamalar :)

--

--