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