Exception Handling ve Transaction İlişkisi
Merhaba arkadaşlar
Bugün çokça kullandığımız exception handling ve Spring Framework’un @transaction. anotasyonu üzerine bir örnekleme yapacağım. Öncelikle kısaca exception handling nedir? Bu konuya değinelim.
Exception handling yani Türkçesi; oluşan istisnaların sarmallanması durumudur. Fark ettiyseniz hata sarmallanması demedim. Çünkü exception handling’in tek amacı hata sarmallamak değildir. Kodunuzdaki istisnai durumları yönetmektir. Tabi genel olarak hata durumlarını sarmallamak ve aksiyon almak isteriz bu nedenle hata sarmallamak olarak kodlanmış olabilir zihnimizde.
Exception türlerinden bahsetmeyeceğim incelemek icin linki tıklayabilirsiniz
Asıl konumuza gelecek olursak; Bugün Spring Framework’un Transactional anotasyonunu kullanırken istisna sarmallamanın öneminden bahsedeceğim.
Spring framework transactional yönetimini anotasyon ve onların propagationlarını kullanarak çok güzel bir şekilde yapmakta. Örnek verecek olursak bir save işlemi yapıldığı zaman herhangi bir istisna durumunda (kaydedilecek verinin üzerinde nullpointerexception olması) kaydetme işlemi olmayacak ve rollback olacaktır.
Transactional işlemler çalıştırıldığı metodlarin ‘{}’ süslü parantezleri açılıp kapanıncaya kadar herhangi bir hata olmaması durumda commit işlemini gerçekleştirir. Aksi durumda butun işlemler rollback olacaktır.
Örnek verecek olursak:
@Transactional
public EntityServiceResult<DiscountDto> saveAndUploadFileAndSendMail(DiscountDto discountDto, List<MultipartFile> files) {
1. EntityServiceResult<DiscountDto> saveDiscount = save(discountDto);
2. uploadFile(files);
3. sendMail(discountDto);
return save;
}
Yukarıda ki kod blogunu incelediğimiz zaman saveAndUploadFileAndSendMail() metodu içerisinde 3 ayrı metod işlem yapmaktadır. saveAndUploadFileAndSendMail() metodu transactional bir metod olduğu icin süslü parantez({}) açılışından itibaren sağlıklı bir şekilde kapanana kadar herhangi bir istisna durumunda butun islemler geri alınacaktır. Bu ne demek oluyor?
- adımda veritabanına discount kaydı atılıyor.
- adımda farklı bir tabloya file kaydediliyor.
- adımda ise kullanıcıya mail atılıyor.
1.adımda discount kaydetme islemi sağlıklı bir şekilde yapılsın. 2. adıma geçtiğimizde veritabanına file ekleme işleminde herhangi bir hata oluştuğu zaman ne olur? yukarıda transactional anotasyonu bulunduğu icin 1. adımda yapılan discount save islemi de rollback olacaktır. Ve veritabanına hiçbir kayıt olmayacaktır. Veya ilk iki adim basarili bir sekilde tamamlanmış olsun. ama mail sırasında alınacak herhangi bir hata 1. ve 2. adımlarda yapılan kayıt islemlerini de rollback edecektir.
Peki buraya kadar her şey çok güzel. Ama karşımıza su sekilde bir case gelirse ne yapabiliriz. Elimizde kişilerin adreslerini güncellediğimiz bir kod olsun. Ve 100bin adet kisi adresi güncellemesi gerekiyor. ve bu servisimizin başında Transactional anotasyonu var. yani ben 99 999. veriyi güncellerken bir istisna durumu ile karşılaşırsam koskocaman liste rollback olacak. Bunu önlemenin farklı yöntemleri var tabi. Yani metodumuza farklı bir propagation kullandığımız yeni transactional tanımı yapabiliriz vs. Ama biz en çok kullandığımız yöntem ile bu işi yapalım şimdi.
@Transactional
public void adresGuncelle(List<Kisi> allKisi){
for (Kisi kisi : allKisi) {
try {
Adres adres = new Adres();
adres.setKisi(kisi);
adres.setYazismaAdresi(EnumSecimEH.EVET);
adres.setAdresTuru(EnumAdresTuru.IKAMETGAH);
adres.setAdresDurumu(EnumAdresDurumu.KULLANIMDA)
service.saveAdres(adres);
}
} catch (Exception e) {
AdresTarihce adresTarihce = new AdresTarihce();
adresTarihce.setKisi(kisi);
String hataMesaj = e.getMessage();
adresTarihce.setAciklama(hataMesaj);
adresTarihce.setGuncellendiMi(EnumSecimEH.HAYIR);
adresTarihce.setIslemTarihi(DateService.getTodayDate());
adresTarihce = service.saveAdresTarihce(adresTarihce);
LOGGER.error("Hata oluştu");
}
}
Yukarıdaki kod blogunda allKisi listesi içerisinde 100bin kisi bulunmakta. Bu kişilerin tek tek adresleri güncellenirken hatalı olan verilerde bütün işlemi rollback yapmak yerine bu sekilde sarmallayabiliriz. Çünku Spring transactional anotasyonu sadece sarmallanmamış exceptionlar için işe yaramaktadır.
Yani siz transactional yaptığınız bir class ya da metod içerisinde yine de rollback yapmamasını istediğiniz özel istisnalarınız var ise try-catch yapısını kullanarak Spring’e “Sana bu noktada ihtiyacım yok. Ben bu exceptionların farkındayım bunlar icin benim islemlerimi geri alma” diyebilirsiniz.
Bug’sız günler :)