1. Giriş
1.1. Objectifs
Belgenin PDF versiyonu |BURADA| adresinde mevcuttur.
Belgedeki örnekler |BURADA| adresinde mevcuttur.
Bu belgede, API JPA (Java Persistence API) ile veri kalıcılığının temel kavramlarını keşfetmeyi amaçlıyoruz. Bu belgeyi okuduktan ve örnekleri test ettikten sonra, okuyucu kendi başına ilerleyebilmek için gerekli temel bilgileri edinmiş olacaktır.
API JPA, nispeten yeni bir teknolojidir. Bu teknoloji, ancak JDK 1.5 sürümünden itibaren kullanılabilir hale gelmiştir. JPA katmanı, çok katmanlı bir mimaride yer alır. Oldukça yaygın olan üç katmanlı bir mimariyi ele alalım:
![]() |
- Burada [ui] (Kullanıcı Arayüzü) olarak adlandırılan [1] katmanı, bir Swing grafik arayüzü, konsol arayüzü veya web arayüzü aracılığıyla kullanıcıyla etkileşime giren katmandır. Bu katmanın görevi, kullanıcıdan gelen verileri [2] katmanına iletmek ya da [2] katmanı tarafından sağlanan verileri kullanıcıya sunmaktır.
- [2] katmanı (burada [metier] olarak anılmaktadır), iş kuralları olarak adlandırılan c.a.d kurallarını uygulayan katmandır. Uygulamaya özgü mantık, kendisine verilen verilerin nereden geldiğini veya ürettiği sonuçların nereye gittiğini dikkate almadan çalışır.
- [3] katmanı, burada [dao] (Veri Erişim Nesnesi) olarak anılan bu katman, [2] katmanına önceden kaydedilmiş verileri (dosyalar, veritabanları, ...) sağlayan ve [2] katmanı tarafından sağlanan sonuçların bir kısmını kaydeden katmandır.
- [JDBC] katmanı, Java'da veritabanlarına erişmek için kullanılan standart katmandır. Bu, genellikle SGBD'in Jdbc sürücüsü olarak adlandırılır.
Geliştiricilerin bu farklı katmanları yazmasını kolaylaştırmak için birçok çaba sarf edilmiştir. Bunlardan biri olan JPA, kalıcı verileri yöneten [dao] katmanının yazılmasını kolaylaştırmayı amaçlamaktadır; bu nedenle bu katmana API (Java Persistence API) adı verilmiştir. Son yıllarda bu alanda öne çıkan bir çözüm ise Hibernate’tir:
![]() |
[Hibernate] katmanı, geliştirici tarafından yazılan [dao] katmanı ile [Jdbc] katmanı arasına yerleştirilir. Hibernate, bir ORM (Nesne-İlişkisel Eşleme) aracıdır; veritabanlarının ilişkisel dünyası ile Java tarafından işlenen nesnelerin dünyası arasında köprü kurar. [dao] katmanının geliştiricisi, artık [Jdbc] katmanını veya içeriğini kullanmak istediği veritabanı tablolarını görmez. Yalnızca veritabanının nesne görüntüsünü görür; bu nesne görüntüsü, [Hibernate] katmanı tarafından sağlanır. Veritabanı tabloları ile [dao] katmanı tarafından işlenen nesneler arasındaki köprü, temel olarak iki şekilde kurulur:
- XML türündeki yapılandırma dosyaları aracılığıyla
- kod içindeki Java açıklamalarıyla; bu teknik yalnızca JDK 1.5 sürümünden itibaren kullanılabilir
[Hibernate] katmanı, mümkün olduğunca şeffaf olmayı amaçlayan bir soyutlama katmanıdır. Hedeflenen ideal durum, [dao] katmanının geliştiricisinin bir veritabanıyla çalıştığını tamamen göz ardı edebilmesidir. Bu, ilişkisel dünya ile nesne dünyası arasında köprü kuran yapılandırmayı geliştiricinin kendisi yazmadığı takdirde mümkündür. Bu köprünün yapılandırılması oldukça hassas bir iştir ve belirli bir alıştırma gerektirir.
[4] nesne katmanı, BD'in bir yansıması olarak "kalıcılık bağlamı" olarak adlandırılır. Hibernate’e dayanan bir [dao] katmanı, kalıcılık bağlamındaki nesneler üzerinde kalıcılık işlemleri (CRUD, create - read - update - delete) gerçekleştirir; bu işlemler Hibernate tarafından SQL komutlarına dönüştürülür. Veritabanı sorgulama işlemleri için (SQL Select), Hibernate, geliştiriciye BD'in kendisini değil, [4] kalıcılık bağlamını sorgulamak için HQL (Hibernate Sorgu Dili) dilini sağlar.
Hibernate popüler olmakla birlikte, ustalaşması zordur. Genellikle kolay olarak sunulan öğrenme eğrisi, aslında oldukça diktir. Bir-çok veya çok-çok ilişkileri içeren tablolara sahip bir veritabanı söz konusu olduğunda, ilişkisel-nesne köprüsünün yapılandırılması, yeni başlayanlar için kolay bir iş değildir. Yapılandırma hataları, uygulamaların performansının düşmesine neden olabilir.
Ticari dünyada, Toplink adında Hibernate’e eşdeğer bir ürün vardı:
![]() |
ORM ürünlerinin başarısı üzerine, Java'nın yaratıcısı Sun, Java 5 ile aynı zamanda ortaya çıkan JPA adlı bir spesifikasyon aracılığıyla bir ORM katmanını standartlaştırmaya karar verdi. JPA spesifikasyonu, hem Toplink hem de Hibernate ürünleri tarafından uygulandı. Ticari bir ürün olan Toplink, o zamandan beri açık kaynaklı bir ürün haline geldi. JPA ile önceki mimari şu şekilde değişti:
![]() |
[dao] katmanı artık bir arayüzler kümesi olan JPA spesifikasyonuyla etkileşim halindedir. Geliştirici, bu sayede standardizasyon açısından kazanç sağlamıştır. Önceden, ORM katmanını değiştirdiğinde, belirli bir ORM ile iletişim kurmak üzere yazılmış olan [dao] katmanını da değiştirmek zorundaydı. Artık, JPA katmanıyla iletişim kuracak bir [dao] katmanı yazacaktır. Bunu uygulayan ürün ne olursa olsun, JPA katmanının [dao] katmanına sunduğu arayüz aynı kalır.
Bu belgede, çeşitli alanlarda JPA örnekleri sunulacaktır:
- Öncelikle, ORM katmanının oluşturduğu ilişki/nesne köprüsüne odaklanacağız. Bu köprü, aşağıdaki türde tablo ilişkilerinin bulunduğu veritabanları için Java 5 anotasyonları kullanılarak oluşturulacaktır:
- bir-bir
- bir-çok
- birden çok - birden çok
Bu alanı örneklemek için aşağıdaki test mimarilerini oluşturacağız:
![]() |
Test programlarımız, JPA katmanını doğrudan sorgulayacak konsol uygulamaları olacaktır. Bu vesileyle, JPA katmanının temel yöntemlerini keşfedeceğiz. "Java SE" (Standard Edition) olarak adlandırılan bir ortamda çalışacağız. JPA, hem Java SE hem de Java EE5 (Enterprise Edition) ortamlarında çalışır.
- Hem ilişkisel/nesne köprüsünün yapılandırmasını hem de JPA katmanındaki yöntemlerin kullanımını öğrendikten sonra, daha klasik bir çok katmanlı mimariye geri döneceğiz:
![]() |
[JPA] katmanına, [metier] ve [dao]'ten oluşan 2 katmanlı bir mimari aracılığıyla erişilecektir. Bu katmanları birbirine bağlamak için Spring [7] çerçeve yapısı ve ardından JBoss'in EJB3 konteyneri kullanılacaktır.
Yukarıda, JPA'in SE ve EE5 ortamlarında kullanılabilir olduğunu belirtmiştik. EE5 Java ortamı, kalıcı verilere erişim alanında bağlantı havuzları, işlem yöneticileri gibi birçok hizmet sunar. Bir geliştirici için bu hizmetlerden yararlanmak faydalı olabilir. EE5 Java ortamı henüz yaygın değildir (Mayıs 2007). Şu anda Sun Application Server 9.x (Glassfish) uygulama sunucusunda bulunur. Bir uygulama sunucusu, esasen bir web uygulaması sunucusudur. Swing türü bağımsız bir grafik uygulama geliştirildiğinde, EE ortamından ve bu ortamın sunduğu hizmetlerden yararlanmak mümkün değildir. Bu bir sorundur. Artık "bağımsız" EE ve c.a.d ortamları görülmeye başlanmıştır. Uygulama sunucusu dışında kullanılabilen ortamlar. Bu belgede kullanacağımız JBos ve EJB3 de bu türden ortamlardır.
Bir EE5 ortamında, katmanlar EJB (Enterprise Java Bean) adı verilen nesnelerle uygulanır. EE'in önceki sürümlerinde, EJB'lerin (EJB, 2.x) uygulanması ve test edilmesi zor olduğu ve bazen düşük performans gösterdiği bilinmektedir. EJB2.x "entity" ve EJB2.x "session" arasında bir ayrım yapılır. Kısaca, bir EJB2.x "entity", bir veritabanı tablosundaki satırın görüntüsüdür ve EJB2.x "session" ise çok katmanlı bir mimaride [metier], [dao] katmanlarını uygulamak için kullanılan bir nesnedir. EJB ile uygulanan katmanlara yöneltilen başlıca eleştirilerden biri, bunların yalnızca EJB kapsayıcıları içinde kullanılabilmesidir; bu kapsayıcılar, EE ortamı tarafından sağlanan bir hizmettir. Bu durum, birim testlerini zorlaştırmaktadır. Dolayısıyla yukarıdaki şemada, EJB ile oluşturulan [metier] ve [dao] katmanlarının birim testleri, bir uygulama sunucusunun kurulmasını gerektirecektir; bu oldukça zahmetli bir işlemdir ve geliştiricinin sık sık test yapmasını pek teşvik etmez.
Spring çerçevesi, EJB2'lerin karmaşıklığına bir tepki olarak ortaya çıkmıştır. Spring, bir SE ortamında, genellikle EE ortamları tarafından sağlanan hizmetlerin önemli bir kısmını sunar. Dolayısıyla, burada ilgilendiğimiz "Veri Kalıcılığı" bölümünde Spring, uygulamaların ihtiyaç duyduğu bağlantı havuzlarını ve işlem yöneticilerini sağlar. Spring'in ortaya çıkışı, bir anda uygulanması çok daha kolay hale gelen birim test kültürünü teşvik etmiştir. Spring, bir uygulamanın katmanlarının klasik Java nesneleri (POJO, Plain Old/Ordinary Java Object) ile uygulanmasına olanak tanıyarak, bunların başka bir bağlamda yeniden kullanılmasını sağlar. Son olarak, Hibernate, Ibatis gibi kalıcılık araçları başta olmak üzere birçok üçüncü taraf aracını oldukça şeffaf bir şekilde entegre eder.
Java EE5, önceki EE spesifikasyonundaki eksiklikleri gidermek üzere tasarlanmıştır. EJB ve 2.x, EJB3 haline gelmiştir. Bunlar, bir EJB3 konteyneri içindeyken onları özel nesneler haline getiren açıklamalarla etiketlenmiş POJOs'lerdir. Bu kapsayıcı içinde, EJB3, kapsayıcının hizmetlerinden (bağlantı havuzu, işlem yöneticisi vb.) yararlanabilecektir. EJB3 konteynerinin dışında, EJB3 normal bir Java nesnesi haline gelir. EJB anotasyonları göz ardı edilir.
Yukarıda, Spring ve JBoss ile EJB3'i, çok katmanlı mimarimizin olası bir altyapısı (çerçeve) olarak gösterdik. İhtiyacımız olan hizmetleri (bağlantı havuzu ve işlem yöneticisi) sağlayacak olan bu altyapıdır.
- Spring ile katmanlar, POJOs'ler kullanılarak uygulanacaktır. Bu POJOs'ler, Spring hizmetlerine (bağlantı havuzu, işlem yöneticisi) bu POJOs'lere bağımlılık enjeksiyonu yoluyla erişecektir: bu POJOs'ler oluşturulurken, Spring onlara ihtiyaç duyacakları hizmetlere ilişkin referansları enjekte eder.
-
JBoss EJB3, bir uygulama sunucusunun dışında çalışabilen bir EJB konteyneridir. Çalışma prensibi (geliştirici açısından) Spring için açıklananla benzerdir. Aralarında çok az fark vardır.
-
Bu belgeyi, basit ancak yine de temsil edici nitelikteki üç katmanlı bir web uygulaması örneğiyle sonlandıracağız:
![]() |
1.2. Références
[ref1]: Java Persistence with Hibernate, Christian Bauer ve Gavin King tarafından yazılmış, Manning yayınevi.
[ref1], aşağıdakilerin temelini oluşturan belgedir. Bu, Hibernate'in iki farklı bağlamda (JPA ile veya JPA olmadan) kullanımına dair 800 sayfadan fazla kapsamlı bir kitaptır. JPA olmadan Hibernate kullanımı, JDK 1.4 veya daha eski sürümlerini kullanan geliştiriciler için hâlâ günceldir, çünkü JPA, JDK 1.5 sürümüyle birlikte ortaya çıkmıştır.
Kitabın dörtte üçünden fazlasını okuduktan ve geri kalanını gözden geçirdikten sonra, bu belgedeki her şeyin yararlı olduğu kanısına vardım. Hibernate konusunda bilgili bir kullanıcı, 800 sayfada verilen bilgilerin neredeyse tamamını bilmelidir. Christian Bauer ve Gavin King, asla karşılaşmayacağımız durumları açıklamak için nadiren ayrıntıya girmiş olsalar da, konuyu kapsamlı bir şekilde ele almışlardır. Her şey okunmaya değer. Kitap eğitici bir üslupla yazılmış: hiçbir konuyu belirsiz bırakmama konusunda gerçek bir özen var. Kitabın, hem JPA ile hem de JPA olmadan Hibernate kullanımı için yazılmış olması, bu teknolojilerden sadece biriyle ilgilenenler için bir zorluk teşkil ediyor. Örneğin, yazarlar çok sayıda örnek üzerinden her iki bağlamda da ilişkisel/nesne köprüsünü anlatıyorlar. Kullanılan kavramlar birbirine çok yakındır, zira JPA, Hibernate’ten büyük ölçüde esinlenmiştir. Ancak aralarında bazı farklılıklar da bulunmaktadır. Öyle ki, Hibernate için geçerli olan bir şey, JPA için geçerli olmayabilir ve bu da okuyucuda kafa karışıklığına yol açmaktadır.
Yazarlar, bir EJB3 konteyneri bağlamında üç katmanlı uygulama örnekleri göstermektedir. Spring'den bahsetmemektedirler. Bir örnek üzerinden göreceğiz ki, Spring'in kullanımı daha basit ve [ref1]'te kullanılan JBoss EJB3 konteynerine kıyasla daha kapsamlı bir amaca yöneliktir. Bununla birlikte, “Java Persistence with Hibernate” kitabı, ORM ile ilgili öğrenebileceğiniz tüm temel bilgileri içerdiği için tavsiye ettiğim mükemmel bir kitaptır.
Bir ORM kullanmak, yeni başlayanlar için karmaşıktır.
- İlişkisel/nesne köprüsünü yapılandırmak için anlaşılması gereken kavramlar vardır.
- "Kalıcı", "ayrılmış" ve "yeni" durumlarındaki nesnelerle ilgili kavramları içeren kalıcılık bağlamı kavramı vardır
- Kalıcılıkla ilgili mekanizmalar (işlemler, bağlantı havuzları) vardır; bunlar genellikle bir kapsayıcı tarafından sağlanan hizmetlerdir
- Performans için yapılması gereken ayarlar vardır (ikinci seviye önbellek)
- ...
Bu kavramları örnekler üzerinden tanıtacağız. Bunlar hakkında çok fazla teorik açıklamaya girmeyeceğiz. Amacımız, her seferinde okuyucunun örneği anlamasını ve örneği kendi içselleştirmesini sağlamak; böylece okuyucunun örnekte kendi başına değişiklikler yapabilmesini veya örneği başka bir bağlamda yeniden uygulayabilmesini sağlamaktır.
1.3. Kullanılan araçlar
Bu belgedeki örneklerde aşağıdaki araçlar kullanılmaktadır. Bazıları eklerde açıklanmıştır (indirme, kurulum, yapılandırma, kullanım). Bu durumda, paragraf numarası ve sayfa numarası belirtilmiştir.
- bir JDK 1.6 (5.1. paragraf)
- Eclipse 3.2.2 Java geliştirme eklentisi IDE (paragraf 5.2)
- Eclipse eklentisi WTP (Web Araçları Paketi) (paragraf 5.2.3)
- Eclipse SQL Explorer eklentisi (5.2.6. paragraf)
- Eclipse Hibernate Tools eklentisi (5.2.5. paragraf)
- Eclipse eklentisi TestNG (paragraf 5.2.4)
- Tomcat 5.5.23 servlet konteyneri (paragraf 5.3)
- SGBD Firebird 2.1 (paragraf 5.4)
- SGBD MySQL5 (paragraf 5.5)
- SGBD PosgreSQL (paragraf 5.6)
- SGBD Oracle 10g Express (paragraf 5.7)
- SGBD SQL Server 2005 Express (paragraf 5.8)
- SGBD HSQLDB (paragraf 5.9)
- SGBD Apache Derby (5.10. paragraf)
- Spring 2.1 (paragraf 5.11)
- JBoss'in EJB3 konteyneri (paragraf 5.12)
1.4. 'daki örneklerin indirilmesi
Bu belgenin web sitesinde, incelenen örnekler bir zip dosyası olarak indirilebilir; bu dosya açıldığında aşağıdaki klasör oluşur:
![]() |
- [1]: örneklerin dizin yapısı
- [2]: <annexes> klasörü, ANNEXES bölümünün 5. paragrafında sunulan öğeleri içerir. Özellikle, <jdbc> klasörü, öğreticideki örnekler için kullanılan SGBD'in JDBC sürücülerini içerir.
- [3]'te: <lib> klasörü, öğretici tarafından kullanılan çeşitli .jar dosyalarını 5 klasör altında toplar
- [4]'te: <lib/divers> klasörü şu arşivleri içerir: - SGBD'teki JDBC sürücüleri - birim test aracı [testNG] - [log4j] günlük aracı
![]() |
- [5]: JPA/Hibernate uygulaması ve Hibernate için gerekli üçüncü taraf araçların arşivleri
- [6]'e: JPA/Toplink uygulamasının arşivleri
- [7]: Spring 2.x ve Spring için gerekli üçüncü taraf araçların arşivleri
- [8]: EJB3 konteyner arşivleri (JBoss)
![]() |
- [9]'te: <hibernate> klasörü, JPA/Hibernate kalıcılık katmanı ile işlenen örnekleri içerir
- [10]'te: <hibernate/direct> klasörü, JPA katmanının [Main] türünde bir programla doğrudan kullanıldığı örnekleri içerir.
- [11] ve [12]'te: JPA katmanının, çok katmanlı bir mimaride [metier] ve [dao] katmanları aracılığıyla kullanıldığı örnekler; bu, normal kullanım durumudur. [metier] ve [dao] katmanları tarafından [metier] ve [dao] katmanları tarafından kullanılan hizmetler, ya Spring [11] ya da JBoss, EJB3 ve [12] katmanlarından sağlanır.
![]() |
- [13]'te: <toplink> klasörü, <hibernate> [9] klasöründeki örnekleri içerir, ancak bu sefer JPA/Hibernate yerine JPA/Toplink kalıcılık katmanı kullanılır.[13]'te <jbossejb3> klasörü bulunmamaktadır; çünkü kalıcılık katmanının Toplink tarafından, hizmetlerin ise JBoss'teki EJB3 konteyneri tarafından sağlandığı bir örneği çalıştırmak mümkün olmamıştır.
- [14]'te: bir <web> klasörü, JPA kalıcılık katmanına sahip üç web uygulaması örneğini bir araya getirir:
- [15]: Spring / JPA / Hibernate ile bir örnek
- [16]: Spring / JPA / Toplink ile aynı örnek
- [17]: JBoss, EJB3 ve JPA / Hibernate ile aynı örnek. Bu örnek, muhtemelen henüz açıklığa kavuşturulamamış bir yapılandırma sorunu nedeniyle çalışmamaktadır. Yine de okuyucunun bu örneği inceleyip, belki de bu soruna bir çözüm bulabilmesi için burada bırakılmıştır.
Öğretici, özellikle incelenen örneklerin testleri sırasında sık sık bu dizin yapısına atıfta bulunur. Okuyucunun bu örnekleri indirip kurması önerilir. Bundan sonra, yukarıda açıklanan örnek dizin yapısına <örnekler> adını vereceğiz.
1.5. 'daki örneklerin Eclipse projelerinin yapılandırılması
Örneklerde “kullanıcı” kütüphaneleri kullanılmaktadır. Bunlar, tek bir isim altında bir araya getirilmiş .jar dosyalarıdır. Böyle bir kütüphaneyi bir Java projesinin classpath dosyasına eklediğinizde, kütüphanenin içerdiği tüm dosyalar bu sınıf yoluna eklenir. Eclipse’te bunun nasıl yapıldığını görelim:
![]() |
- [1]'te: [Window / Preferences / Java / Buld Path / User Libraries]
- [2]'e: yeni bir kütüphane oluşturulur
- [3]: Kütüphaneye bir ad verip onaylayın
![]() |
- [4]'te: kütüphaneye eklenecek jar dosyalarını seçiyoruz [jpa-divers]
- [5]: <exemples>/lib/divers klasöründeki tüm JAR dosyalarını seçiyoruz
![]() |
- [6]'te: [jpa-divers] kullanıcı kütüphanesi tanımlandı
- [7]: Aynı işlemi tekrarlayarak 4 kütüphane daha oluşturulur:
Kütüphane | Kütüphanenin jar dosyalarının bulunduğu klasör |
<örnekler>/lib/hibernate | |
<örnekler>/lib/toplink | |
<örnekler>/lib/spring | |
<örnekler>/lib/jbossejb3 |













