Banyak cara untuk meningkatkan performa aplikasi yang kita buat menggunakan framework Hibernate. Salah satunya adalah menggunakan fasilitas second-level cache. Data-data yang tidak sering berubah seperti data-data referensi atau master sangatlah cocok untuk ditempatkan di cache. Dengan begitu beban database dapat dikurangi secara signifikan.
Kita tentu saja dapat membuat sendiri mekanisme caching objek di aplikasi kita. Namun hal tersebut mengharuskan kita untuk memelihara objek-objek yang ada di cachenya. Terutama saat objek tersebut dihapus atau diupdate. Selain itu source code kita juga akan dipenuhi oleh code-code yang digunakan untuk mengambil data dari cache tersebut.
Bila kita menggunakan Hibernate Cache maka hal di atas tidak perlu kita lakukan karena proses caching di Hibernate sangatlah transparan. Cukup tambahkan satu konfigurasi di hibernate.cfg.xml dan annotation di setiap class yang akan kita cache maka fasilitas caching sudah dapat dimanfaatkan.
Di Hibernate terdapat dua level cache yaitu first level cache dan second level cache.
First level cache terletak pada objek Session
itu sendiri. Bila kita read()
dua kali atau lebih dengan id sama, maka Hibernate hanya meng-query satu kali saja ke database. Objek hasil query kemudian disimpan di memori. Objek inilah yang akan diberikan untuk pemanggilan read selanjutnya. Objek tersebut hidup di dalam cache selama session tersebut aktif.
Second level cache digunakan saat kita ingin mengcache objek-objek lintas Session
. Artinya masa hidup objek tersebut tidak lagi bergantung pada siklus hidup Session tapi diatur oleh mekanisme lain.
Untuk lebih memahami kedua jenis cache kita ambil contoh sebuah class Category
.
Class Category
ini merupakan sebuah class persistence sederhana yang dipetakan pada sebuah tabel category
dengan kolom id
dan name
.
Untuk menunjukkan fungsi first-level cache maka kita baca sebuah objek Category
dengan id 1
sebanyak lima kali. Hal tersebut kita lakukan di program berikut:
Bila program di atas dijalankan maka berikut ini adalah outputnya:
Hibernate: select category0_.id as id0_0_, category0_.name as name0_0_ from category category0_ where category0_.id=?
Sepatu
Sepatu
Sepatu
Sepatu
Sepatu
Dari output di atas terbukti bahwa dengan adanya first-level cache, maka kita dapat mengurangi beban database sebesar 80% sehingga data dapat dibaca dengan lebih cepat. Masih berani bilang kalau Hibernate itu lambat?
Berbeda dengan first-level cache yang sepenuhnya dikelola oleh Hibernate, pada second-level cache Hibernate berkolaborasi dengan cache provider. Cache provider merupakan library/framework yang berfungsi untuk meng-cache objek. Masing-masing cache provider memiliki cara masing-masing dalam menerapkan fungsi caching. Implementasi caching tidak melulu di memori, beberapa provider menyediakan fasilitas untuk meng-cache objek ke disk. Berikut ini adalah cache provider yang populer di kalangan programmer Java:
Pada artikel ini kita akan menggunakan “ehcache” sebagai cache provider. Langkah pertama adalah mendaftarkan dependency baru yaitu hibernate-ehcache
di pom.xml
kita.
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-ehcache</artifactId>
<version>3.6.3.Final</version>
</dependency>
Selanjutnya, kita tambahkan dua property yaitu hibernate.cache.use_second_level_cache
dan hibernate.cache.region.factory_class
di konfigurasi session-factory kita di dalam file hibernate.cfg.xml
.
<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE hibernate-configuration PUBLIC
"-//Hibernate/Hibernate Configuration DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-configuration-3.0.dtd">
<hibernate-configuration>
<session-factory>
<property name="hibernate.cache.use_second_level_cache">true</property>
<property name="hibernate.cache.region.factory_class">net.sf.ehcache.hibernate.EhCacheRegionFactory</property>
<property name="hibernate.connection.driver_class">com.mysql.jdbc.Driver</property>
<property name="hibernate.connection.url">jdbc:mysql://localhost:3306/shop</property>
<property name="hibernate.connection.username">root</property>
<property name="hibernate.connection.password"></property>
<property name="hibernate.dialect">org.hibernate.dialect.MySQL5Dialect</property>
<property name="show_sql">true</property>
<mapping class="com.codequ.hibernate.model.Category" />
<mapping class="com.codequ.hibernate.model.Product" />
</session-factory>
</hibernate-configuration>
Setelah itu kita mesti memberi tahu Hibernate class mana saja yang akan dicache di second-level cache dengan menggunakan annotation yang sudah disediakan.
Selanjutnya untuk membuktikan bahwa objeknya tetap dicache walaupun diakses dari dua atau lebih Session
yang berbeda, maka kita buat sebuah class Data Access Object untuk class Category di atas.
Selanjutnya kita panggil method read()
di class DAO tersebut di sebuah program Java.
Output dari program di atas adalah sebagai berikut:
Hibernate: select category0_.id as id0_0_, category0_.name as name0_0_ from category category0_ where category0_.id=?
Sepatu
Sepatu
Sepatu
Sepatu
Sepatu
Hasilnya sama dengan contoh program first-level cache. Perbedaan dengan first-level cache adalah setiap kali dao.read(1L)
dipanggil, objek category “Sepatu” dibaca dari objek session yang berbeda, namun karena kita sudah mengaktifkan second-level cache untuk class Category
maka objek yang sama yang akan diberikan di setiap session.
Bila kita non-aktifkan konfigurasi Cache pada class Category
lalu menjalankan ulang program di atas, berikut ini adalah outputnya:
Hibernate: select category0_.id as id0_0_, category0_.name as name0_0_ from category category0_ where category0_.id=?
Sepatu
Hibernate: select category0_.id as id0_0_, category0_.name as name0_0_ from category category0_ where category0_.id=?
Sepatu
Hibernate: select category0_.id as id0_0_, category0_.name as name0_0_ from category category0_ where category0_.id=?
Sepatu
Hibernate: select category0_.id as id0_0_, category0_.name as name0_0_ from category category0_ where category0_.id=?
Sepatu
Hibernate: select category0_.id as id0_0_, category0_.name as name0_0_ from category category0_ where category0_.id=?
Sepatu
Terlihat bahwa tanpa second-level cache, program di atas akan mengeksekusi lima kali query ke database.
Source code: https://github.com/bustanil/hibernate-caching