Hibernate, C3P0 ve MySQL

Hibernate kullanması güzel fakat ne yazık ki ayarlaması zor bir araç. Her şeyi doğru ayarlamış bile olsanız, zaman içerisinde Hibernate’in size sorun çıkarması mümkün. Diyelim ki bir uygulama geliştiriyorsunuz ve Hibernate kullanıyorsunuz. Üstelik Hibernate’i Spring ya da Seam gibi bir yapıyı kullanmadan yapıyorsanız işiniz var demektir. Hem testlerinizi yazmanız hem hibernate session’larınızı ve tabiki transaction’larınızı kendiniz kontrol etmeniz gerekecek.

C3P0 Hibernate

Şimdiye kadar olan Hibernate yazılarımda Session Kontrolünün ve Veritabanı Testlerinin nasıl yapılması gerektiği üzerine durduk. Fakat herşeyi düzgün yapsanız, tüm testleriniz doğru çalışsa bile Hibernate tarafından sorun çıkmayacağının garantisi yok. Zamana bağlı sorunlar söz konusu ve şimdiden söyliyim bu tip sorunların çıkmasının tek sebebi sizsiniz.

MySQL ve wait_timeout

Öncelikle söyliyim ben veritabanı yöneticisi ya da uzmanı ya da veritabanı ile ilgili herhangi birşey değilim. Hatta veritabanından uzak yaşamayı seven bir adamım. Yinede veritabanının bazı temel noktalarını daha iyi bilmeyi dilerdim. Eğer daha iyi bilseydim bu sorunlarla hiç karşılaşmamış olacaktım.

MySQL veritabanına bağlandığınızda, doğal olarak veritabanı sunucusu sizin işlem yapmanızı beklemektedir. Aynı zamanda üzerindeki bağlantıları minimumda tutmak için belli bir süre işlem yapmayan bağlantıları atmaktadır. Sorun ise Hibernate bağlantılarınıda atıyor olmasında yatıyor. Çünük sunucu bağlantıyı kestiğinde sevgili Hibernate bundan haberdar olamıyor ve işlem yapmaya çalışıyor. Bunun sonucunda ise bir çeşit IOException alıyoruz. Bu hata bize JDBC bağlantısının kapandığını ve bizim bağlantı ardından paket göndermeye çalıştığımızla ilgili oluyor. Doğal olarak test ederken bu hatayı hiç bir şekilde alamıyoruz.

Test sırasında bu hatayı almıyor olmamızın tek nedeni wait_timeout değişkenin değerinin sekiz saat olarak belirlenmesi. Yani bu eğer sekiz saat boyunca işlem yapmazsak bağlantımızın sunucu tarafından koparılacağı anlamına geliyor.

Hatanın Yaratılması

Eğer hatayı tekrardan yaratmak istiyorsanız, ister konsoldan isterseniz MySql Workbanch’ten ya da doğrudan my.ini dosyası içerisinden wait_timeout değerini on saniye falan yapın. Uygulamanızı çalıştırın, ilk veritabanı işlemini yapın ve on saniye kadar bekleyin. Tekrar veritabanı işlemi yaptığınızda istediğiniz hatayı görebileceksiniz.

C3P0

İşte tam bu noktada devrete C3P0 eklentisi devreye giriyor. Genel olarak C3P0 uygulamanızın bağlantılarını yönetiyor. Yani uygulama başlangıcında kaç bağlantı alınacak, bu bağlantılar yetmediğinde yenilerini kaçar kaçar alacağı, fazladan alınan bağlantıların ne kadar zaman sonra boş bırakılacağı gibi özellikleri yönetmektedir. Doğrudan driver üzerinden çalıştığından sorun çıkarmamaktadır. Yani sadece Hibernate kullanırken değil doğrudan MySql Connector kullanırken de C3P0 kullanabilirsiniz. Tabi sadece MySql veritabanını değil, kullanmak isteyeceğiniz tüm veritabanlarını desteklemektedir.

Hibernate kullandığınız projenize C3P0 kullanmak isterseniz tek bağımlılığı eklemeniz yeterli olacaktır. Eğer Maven kullanmıyorsanız, hem hibernate eklentisini hem de C3P0 kütüphanesini indirmeniz gerekecektir. Fakat bu işleri bizim için Maven yaptığından tek bağımlılık yeterli olacaktır.

pom.xml

...
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-c3p0</artifactId>
<version>3.5.6-Final</version>
</dependency>
...

Test için C3P0 Ayarları

C3P0 bağlantının aktif olarak kalması için belirli aralıklarla sunucuya basit bir SQL komutu göndermektedir. Bu sayede kullanılan ya da kullanılma potansiyeli olan hiç bir bağlantı boşa çıkmamaktadır. Ayrıca Hibernate tarafından kullanılma ihtimali kalmayan bir bağlantıda, eğer bağlantı sayısı minimum seviyede değilse, bir süre beklenildikten sonra iade edilir. Bu sebepten C3P0 ayarlarını yaparken dikkatli olun. Aksi halde sunucunuza fazladan yük bindirebilirsiniz.

Aşağıda hibernate.cfg.xml dosyası içerisinde C3P0 ayarlarının nasıl yapıldığıyla ilgili örnek mevcuttur. Bu örnekte kullanılan sayılar 10 saniye wait_timeout olan MySql server içindir. Kendi sunucunuza ait bilgileri göz önüne alarak aşağıdaki değerleri arzu ettiğiniz şekilde değiştiriniz.

hibernate.cfg.xml

...
<property name="hibernate.connection.provider_class">org.hibernate.connection.C3P0ConnectionProvider</property>
<property name="hibernate.c3p0.max_statements">0</property>
<property name="hibernate.c3p0.min_size">1</property>
<property name="hibernate.c3p0.max_size">25</property>
<property name="hibernate.c3p0.timeout">1</property>
<property name="hibernate.c3p0.idle_test_period">1</property>
<property name="hibernate.c3p0.preferredTestQuery">select 1;</property>
<property name="hibernate.c3p0.acquire_increment">1</property>
...

Yukarıdaki ayarları yaptığınızda, eğer wait_timeout ayarlarınız doğru şekilde ayarlandıysa, sorunsuz şekilde bağlantınızın açık kaldığını görecceksiniz. Şimdi burada belirlenen değerli tek tek inceleyelim.

C3P0 Özellikler

[fancy_list style=”circle_arrow” variation=”yellow”]

  • hibernate.connection.provider_class: Bağlantı sağlayıcı olarak hangi sınıfın kullanıldığının belirtilmesi gerekiyor. Biz kendi versiyonumuz için geçerli olanı kullandık. Kendi kullandığınız versiyonda bu değişik olabilir. Bu sınıfın ne olduğunu eklediğimiz bağlımlılığın(.jar dosyasının) içine bakarak öğrenebilirsiniz.

  • hibernate.c3p0.max_statements: C3P0 aynı zamanda sizin için SQL sorgularınıda saklayabiliyor. Bu özellik en fazla ne kadar cümle saklaması gerektiğini belirliyor
  • hibernate.c3p0.min_size: Hibernate çalışmaya başladığında, yani SessionFactory sınıfı oluşturulduğunda kaçtane bağlantı açılacağını belirler.
  • hibernate.c3p0.max_size: C3P0 tarafından enfazla kaç tane bağlantı açılacağını belirler
  • hibernate.c3p0.timeout: Her bağlantının ne kadar zaman boşta kalabileceğini belirler. Bağlantılar Hibernate tarafından bırakıldıktan sonra, timeout süresi kadar bekler ve iade edilirler.
  • hibernate.c3p0.idle_test_period: Kullanılma ihtimali olan bağlantıların ne kadar zamanda bir test edileceğini belirler. Böylelikle hiç bir MySQL bağlantısı, Hibernate izin vermeden boşa çıkamaz.
  • hibernate.c3p0.preferredTestQuery: Hangi sorgu cümleciğiyle bağlantıların test edileceğini bu alandan belirleyebiliyoruz. Genel olarak select 1; ya da select count(id) from tablo; şeklindeki sorgular kullanılıyor.
  • hibernate.c3p0.acquire_increment: Bağlantı miktarı yetmediğinde, C3P0 sunucudan yeni bağlantılar ister. Bu sayı her seferinde kaç tane bağlantı istenileceğini belirler.

[/fancy_list]

Hala Hata Var?

Eğer tüm bu işlemleri yaptıysanız ve hala hata alıyorsanız, DAO sınıflarınızı kontrol ediniz. Genel olarak kullanıcılar, sorgulama yaparken, transaction’larını başlatır fakat sonradan commit’leyip transaction’larını bitirmezler. Bu gibi durumlarda bağlantı hala Hibernate elinde olduğundan, C3P0 bu bağlantıları kontrol etme zahmetine girmez. Çünkü Hibernate bir bağlantıya sahipse veritabanı üzerinde işlem yapıyordur. Daha doğrusu yapmalıdır. Fakat transaction commit edilmediğinde işlem yarım kalır. Zaman içerisinde hibernate bunları temizler ya da başka isteklere aktarsa da bu tip durumlar testlerinizde sorun çıkarır.

Bu sebepten dolayı sorgulama yaparken dahi başlattığınız transaction’larınızı commit işlemi ile sonlandırın.

Kaynak

End Of Line