Merhabalar arkadaşlar. Bu yazıda sizlere EJB’nin özelliklerinden biri olan Container Managed Transaction’ı anlatmaya çalışacağım. Normalde konu JPA ile de ilgili. Fakat Container taraflı olaydan bahsettiğimiz için bunu EJB kısmında anlatmak istedim.
Veri tabanlarındaki tablolarımızı Java koduna dönüştürme (mapping) yaptığımızda ve sınıf vasıtası ile bir operasyon gerçekleştirmek istediğimizde en azından bir EntityManager kullanmak zorundayız. @PersistenceContext notasyonu ile bu EntityManager nesnesinin enjeksiyonunu Container’a bırakabiliyoruz. Bunun yanında kayıt ekleme,silme,güncelleme operasyonları gerçekleşeceği zaman getTransaction.begin() ve getTransaction.commit() işlemlerinin de yapılması lazım ya da bu işlemlerin yapımı sırasında hata meydana gelirse veritabanının işlem öncesi halini korumak için rollback() işleminin yapılması lazım. İşte EJB içinde bu işlemler de istenirse EJB Container’a bırakılabilinir. Şimdi nasıl yapıldığına örnek üzerinden bakalım. Kullanacağım örnek Github hesabımda yer alan HospitalAutomation projesinden alınmadır. Proje şuradadır. Bu yazıda işin özünü anlatacağım ve bu nedenle JSF ve Managed Bean kodlarına değinmeyeceğim bu yazıda. Onları da incelemek isterseniz projenin kaynak kodlarına bakabilirsiniz. savingPatients.xhtml ve SavePatients.java dosyaları JSF taraflı olan dosyalardır.
SavePatientsSessionBean.java
/* * To change this license header, choose License Headers in Project Properties. * To change this template file, choose Tools | Templates * and open the template in the editor. */ package com.ilkgunel.hastaneotomasyonu.ejb; import com.ilkgunel.hastaneotomasyonu.entity.Patients; import javax.ejb.Stateless; import javax.ejb.TransactionAttribute; import javax.ejb.TransactionAttributeType; import javax.ejb.TransactionManagement; import javax.ejb.TransactionManagementType; import javax.persistence.EntityManager; import javax.persistence.PersistenceContext; /** * * @author ilkaygunel */ @Stateless @TransactionManagement(TransactionManagementType.CONTAINER) public class SavePatientSessionBean implements SavePatientSessionBeanLocal { @PersistenceContext(unitName = "HospitalAutomation") private EntityManager em; @Override @TransactionAttribute(TransactionAttributeType.REQUIRED) public String savePatient(Patients patients) { try { em.persist(patients); return "Bilgileriniz Kaydedildi. Sisteme Giriş Yapıp Randevu Alabilirsiniz"; } catch (Exception e) { System.err.println(e); return "Bilgilerin Kaydı Sırasında Bir Hata Meydana Geldi!"; } } }
EJB sınıfımız içinde ilk olarak dikkatinizi sınıfın işaretlendiği notasyona çekmek istiyorum. @TransactionManagement notasyonu bir EJB sınıfının hangi transaction yöntemi ile yönetileceğini bildirir ve içine alacağı parametreye göre davranır. İki çeşit parametre alabilir. Biri Transaction yönetiminin Container’a bırakıldığını bildiren TransactionManagementType.CONTAINER diğeri ise kodu yazana bıraktığını bildiren TransactionManagementType.BEAN.
@PersistenceContext notasyonu ile EntityManager enjeksiyonunu gerçekleştiriyoruz.
Patients tipinde bir parametre alan ve aldığı parametreyi veri tabanına yollayan savePatient metodu @TransactionAttribute notasyonu ile işaretli. Bu notasyon da olarak 6 faklı parametre alabilir.
- TransactionAttributeType.REQUIRED: Bu parametreye ile işaretlenmiş metod mutlaka bir transaction içersinden çağırılmak zorundadır. Eğer nontransactional yani commit ve rollback işlemlerinin garanti edilmediği bir istemciden çağırılırsa bu metot container bizim için transactional yapıyı derhal kurar. Eğer hali hazırda bir transactional yapı var ise ve bu metot çağırılır ise bu metodu mevcut transaction yapısı içinde koşturur.
- TransactionAttributeType.REQUIRES_NEW: Bu parametre ile işaretlenmiş metod çalışabilmek için yeni bir transactional yapıya ihtiyaç duyar ve container tarafından sağlanır. Eğer hali hazırda istemci-sunucu arasında bir transactional yapı varsa geçici olarak bu yapı devre dışı bırakılır.
- TransactionAttributeType.SUPPORTS: Eğer metot bu parametre ile işaretlenirse istemci-sunucu arasında bir transactional yapı olup olmadığına bakılır. Eğer yoksa metot nontransactional bir şekilde koşturulur. Eğer varsa transactional yapı içinde çalıştırılır.
- TransactionAttributeType.NOT_SUPPORTED: Bu parametre ile işaretlenen metot transactional yapı içinde çalışamaz. Bu nedenle metot çağırıldığı sırada transaction varsa geçici olarak durdurulur, metot çalıştırılır ve akabinde transaction devam ettirilir.
- TransactionAttributeType.MANDATORY: Bu parametre ile işaretlenmiş metot çalışabilmek için mutlaka önceden transaction var olmuş olmalıdır ve transaction yoksa container yeni bir transaction sağlamaz.
- TransactionAttributeType.NEVER: Bu parametre ile işaretlenmiş metot da asla transactioal yapı içerisinde çalışamaz. Bu nedenle hiç transaction olmaması gerekir.
Ben bu yazı için Required’ı örnek olarak aldım.
Ekran Çıktıları
Yeni üye kaydı sayfasını şekildeki gibi dolduruyorum.
Kaydet butonuna bastığımda bana kaydın başarılı olduğu şeklinde mesaj döndü. Bir de veritabanına bakalım.
Kayıt gerçekten de başarı ile veritabanına yollanmış.
Bu yazıda transaction mekanizmasının yönetiminin sunucuya bırakılarak nasıl işlem yapılacağını öğrenmiş olduk arkadaşlar. Bu yolla commit, rollback vs. işlemlerin sorumluluğu sunucuya devredilmiş oldu. Ekran çıktılarından gördüğünüz üzere begin ve commit işlemleri sunucu tarafından halledildi.
Gelecek yazıda görüşmek üzere sağlıcakla kalın arkadaşlar.