1 PERSISTENCE LAYER DENGAN ibatis Desember 2009 Tingkat: Oleh : Feri Djuandi Pemula Menengah Mahir Apakah ibatis itu? Secara umum ibatis bisa dijelask...
Apakah iBATIS itu? Secara umum iBATIS bisa dijelaskan sebagai sebuah persistence framework yang mengotomatisasi penjembatanan atau pemetaan (mapping) antara database SQL dan objekobjek di dalam Java. Definisi ini akan sangat membingungkan terutama bagi seseorang yang tidak pernah mengenal iBATIS sebelumnya. Tidak perlu khawatir, mari kita pahami satu-per satu dimulai dari istilah persistence. Pada sebuah sistem aplikasi client-server dengan arsitektur three-tier dikenal tiga buah lapisan (layer) yang disebut sebagai presentasion, business logic dan data. Lapisan-lapisan ini tentunya bukan sesuatu yang asing bagi banyak programmer sehingga tidak perlu banyak dijelaskan di sini. Ilustrasi dari lapisan-lapisan ini diperlihatkan pada gambar di bawah. PRESENTASION
BUSINESS LOGIC
DATA
Gambar 1. Seiring dengan berkembangnya evolusi pemrograman dan ditemukannya teknik-teknik yang baru yang berdasarkan pengalaman diakui dapat meningkatkan efisiensi serta kemudahan maka diperkenalkanlah sebuah lapisan persistence yang berada di antara business logic dan data sehingga yang semula kedua lapisan itu langsung berinteraksi maka sekarang ada jembatan di tengah-tengahnya yang mengatur komunikasi keduanya secara tidak langsung PRESENTASION
www.tobuku.com Perlu dipahami bahwa persistence layer adalah konsep yang umum pada pengembangan sebuah aplikasi dan tidak terkait secara spesifik dengan sebuah teknologi atau produk tertentu. Selain diaplikasikan pada lingkungan Java, persistence layer juga biasa diterapkan pada platform yang lain seperti .NET. Sebuah persistence layer bekerja dengan hal-hal yang berhubungan dengan persisting yaitu penyimpanan (storing) dan pembacaan (retrieving) data ke/dari database. Tujuan yang paling mendasar dari keberadaan sebuah persistence layer adalah: •
Mengambil alih pekerjaan-pekerjaan yang berkaitan dengan persisting dari lapisan business logic (misalnya perintah SELECT, INSERT dan UPDATE) sehingga business logic bisa sungguh-sungguh fokus dengan rangkaian-rangkaian program yang berhubungan dengan logika bisnis, aturan dan aliran program dari aplikasi yang bersangkutan tanpa perlu dipusingkan dengan detail dari perintah-perintah SQL dari database. Dengan demikian, business logic menjadi bebas dan tidak tergantung dengan tipe atau platform database apapun yang digunakan.
•
Memisahkan secara jelas antara kode program dengan perintah-perintah SQL dengan cara mengeluarkan semua perintah operasi database dari business logic. Tujuannya adalah untuk menghindari program yang campur aduk antara kode program dari aplikasi dan perintah-perintah SQL. Hal ini sangat penting untuk kerapihan dan kemudahan dalam memelihara kode program. Dengan demikian embedded SQL atau inline SQL (perintah-perintah SQL yang berbaur dengan kode program) adalah sesuatu yang ingin dihindari oleh persistence framework.
Merujuk pada gambar 2 di atas, tampak bahwa lapisan persistence terbagi menjadi tiga bagian dengan masing-masing fungsi sebagai berikut: 1. Abstraction Layer. Berfungsi sebagai antar muka bagi lapisan persistence agar lapisan business logic dapat berinteraksi dengannya. Bagian inilah yang akan dibahas pada artikel ini. 2. Persistence Framework, dalam hal ini adalah iBATIS itu sendiri. Pada prakteknya iBATIS adalah sebuah library (file JAR) yang diasosiasikan dengan sebuah project Java sehingga class-class di dalam iBATIS dapat digunakan. 3. Driver/Interface. Yang dimaksud driver disini adalah antar muka untuk mengakses database. Driver database yang digunakan dalam pemrograman Java adalah JDBC. Jika Anda tergolong baru dalam menggunakan JDBC, silakan membaca artikel lain yang berjudul “MENGAKSES DATABASE DENGAN JDBC”. Selain iBATIS, persistence framework lainnya yang cukup populer adalah Hybernate. Hybernate dikenal sebagai sebuah perkakas Object/Relation Mapping (O/RM) yang melakukan pemetaan antara objek-objek (class Java) dengan table-table di dalam database secara langsung dimana property-property dari sebuah class harus sama dengan kolom-kolom table yang bersangkutan. Itu sebabnya pemetaan struktur antara objek dan table harus sama persis.
-2-
www.tobuku.com
Class Person identifier firstName lastName middleName hairColor height weight
Table PERSON
Pemetaan langsung. Class Person harus klop dengan table PERSON
ID FIRST_NAME LAST_NAME MIDDLE_NAME HAIR_COLOR HEIGHT WEIGHT
Gambar 3. Berbeda dengan Hybernate, iBATIS bukanlah sebuah perkakas O/RM melainkan sebuah perkakas Query Mapping karena iBATIS tidak memetakan struktur table dengan sebuah class secara langsung, namun melalui perintah-perintah SQL (SELECT, INSERT, UPDATE atau DELETE). Pemetaan pada iBATIS memiliki fleksibilitas tinggi, selain itu programmer memiliki kontrol lebih besar terhadap perintah-perintah SQL dan kebebasan lebih dalam kustomisasi. Class Person identifier firstName lastName middleName hairColor height weight
SELECT ID as identifier FIRST_NAME as firstName LAST_NAME as lastName MIDDLE_NAME as middleName HAIR_COLOR as hairColor HEIGHT as height WEIGHT as weight FROM PERSON WHERE ID=#identifier#
Table PERSON ID FIRST_NAME LAST_NAME MIDDLE_NAME HAIR_COLOR HEIGHT WEIGHT
Gambar 4. Masing-masing pendekatan antara Hybernate dan iBATIS memiliki kelebihan dan kekurangan, namun keduanya memiliki fungsi yang sama sebagai sebuah persistence layer.
-3-
www.tobuku.com
Persiapan Sebelum Memulai Sebelum melanjutkan pembahasan iBATIS, silakan mempersiapkan hal-hal sebagai berikut yang akan dibutuhkan selama penjelasan di dalam artikel ini: 1. Library iBATIS Library iBATIS tersedia secara gratis dengan cara men-download-nya melalui situs web: http://ibatis.apache.org/ Pada artikel ini versi iBATIS yang digunakan adalah iBATIS Java 2.3.4. Anda memiliki kebebasan untuk menggunakan versi yang lebih baru. Kecuali ada hal-hal yang disebutkan secara khusus, seharusnya contoh-contoh program di dalam artikel ini dapat berjalan dengan baik pada iBATIS versi yang lebih baru. 2. JDBC driver Database yang digunakan pada contoh-contoh program adalah Ms SQL Server. Ada sejumlah JDBC driver untuk Ms SQL Server yang tersedia di pasaran, namun salah satu yang cukup baik dan teruji dalam penggunaannya adalah jTDS. JDBC driver ini dapat diperoleh secara gratis dari situs web: http://jtds.sourceforge.net/ jDTS yang dipergunakan dalam contoh program ini adalah versi 1.2.4, namun sekali lagi - Anda memiliki kebebasan untuk menggunakan versi yang lebih baru.
-4-
www.tobuku.com
Mengasosiasikan Project dengan iBATIS Framework Setelah langkah-langkah persiapan di atas selesai dilakukan, maka kita bisa mulai menggunakan iBATIS. 1. Jalankan Eclipse dan buatlah sebuah Java Project.
2.
Beri nama project tersebut sebagai persist-exercise01. Klik tombol Finish.
-5-
www.tobuku.com 3. Dengan menggunakan Windows Explorer, buatlah sebuah sub-folder di dalam folder project tersebut dan beri nama lib.
4. Copy-kan file-file library iBATIS dan jTDS ke dalam sub-folder tersebut. Pada contoh ini file yang dimaksud adalah: •
ibatis-2.3.4.726.jar
•
jtds-1.2.2.jar
Nama file-file di atas akan berbeda tergantung dari versi library yang dipergunakan. 5. Kembali kepada Eclipse, klik kanan pada folder project persist-exercise01 dan atur konfigurasi Build Path.
-6-
www.tobuku.com
6. Klik tombol “Add External JARs” dan tambahkan kedua file JAR yang ada di dalam folder lib tadi.
7. Setelah file-file library ditambahkan, tekan tombol F5 untuk me-refresh tampilan pada Package Explorer. Seperti diperlihatkan pada gambar di bawah ini, tampak bahwa kedua library telah diasosiasikan dengan project ini.
Anda telah selesai mengaosiasikan sebuah project dengan iBATIS Framework. Silakan ikuti uraian berikutnya untuk melihat bagaimana framework ini dipergunakan. -7-
www.tobuku.com
Program Sederhana dengan iBATIS Framework Untuk alasan kemudahan dalam memahami penggunaan iBATIS bagi pemula, maka uraian ini dibagi menjadi empat tahap sebagai berikut: 1. Menentukan konfigurasi koneksi database 2. Membuat model 3. Membuat pemetaan SQL dari table dengan model 4. Membuat implementasi
Menentukan konfigurasi koneksi database Di dalam membuat sebuah aplikasi berbasis database, tidak peduli aplikasi tersebut besar atau kecil, sederhana atau kompleks – selalu ada satu hal yang sama: membuat koneksi ke database. Hal tersebut juga berlaku pada iBATIS. Langkah pertama yang harus dilakukan adalah menentukan parameter-parameter koneksi yang digunakan untuk terhubung ke sebuah database. 1. Jalankan Eclipse dan buat sebuah package melalui menu New Package. Beri nama sebagai org.exercise01.persist.dao.
-8-
www.tobuku.com
2. Buat sebuah file XML di dalam package di atas melalui menu New Other, kemudian pilih XML.
Beri nama file XML tersebut sebagai SqlMapConfig.xml.
-9-
www.tobuku.com
3. Salin kode program di bawah ini ke dalam file tersebut. Kode program ini tentunya harus dimodifikasi untuk disesuaikan dengan kebutuhan Anda. Seperti yang dijelaskan sebelumnya, pembahasan artikel ini menggunakan database SQL Server itu sebabnya JDBC driver yang digunakan adalah jTDS (lihat property JDBC.Driver pada program di bawah). Anda memiliki kebebasan untuk menggunakan database yang lain seperti MySQL atau Oracle, namun pastikan menggunakan JDBC driver yang sesuai pula. Kode program 1 . SqlMapConfig.xml. <sqlMapConfig> <property name="JDBC.Driver" value="net.sourceforge.jtds.jdbc.Driver" /> <property name="JDBC.ConnectionURL" value="jdbc:jtds:sqlserver://127.0.0.1/Northwind" /> <property name="JDBC.Username" value="sa" /> <property name="JDBC.Password" value="" /> <sqlMap resource="org/exercise01/persist/dao/Employee.xml" />
Selanjutnya property JDBC.ConnectionURL berisi nama server dan database. Hal ini pun harus disesuaikan JDBC driver yang digunakan karena masing-masing driver memiliki aturan penulisan parameter yang berbeda-beda. Pada contoh ini server yang digunakan adalah komputer lokal dimana alamat IP nya ditandai dengan 127.0.0.1 yang merupakan standar IP lokal. Sementara itu, database SQL Server yang digunakan bernama Northwind. Akhirnya, property resource pada bagian sqlMap merujuk pada definisi pemetaan SQL yang akan dijelaskan pada bagian berikutnya beberapa saat lagi. Untuk sekarang cukup simpan semua perubahan yang dilakukan pada file tersebut.
-10-
www.tobuku.com
4. Buat sebuah class di dalam package yang sama melalui menu New Class. Beri nama class tersebut sebagai DaoFactory dan salin kode program di bawah ini ke dalamnya. Kode program 2. DaoFactory.java. package org.exercise01.persist.dao; import java.io.Reader; import com.ibatis.common.resources.Resources; import com.ibatis.sqlmap.client.SqlMapClient; import com.ibatis.sqlmap.client.SqlMapClientBuilder; public class DaoFactory { private static SqlMapClient instance; public static SqlMapClient getSqlMapClient() throws Exception { if(instance == null) { try { Reader reader = Resources.getResourceAsReader ("org/exercise01/persist/dao/SqlMapConfig.xml"); instance = SqlMapClientBuilder.buildSqlMapClient(reader); } catch (Exception ex) { throw ex; } } return instance; } }
Kode program di atas cukup standar dan tidak perlu diubah (kecuali mungkin nama package pada baris paling atas), oleh karena itu nantinya file Java dari class ini dapat disimpan dan digunakan untuk aplikasi-aplikasi yang lain.
-11-
Membuat Model Model yang dimaksud dalam konteks ini adalah model entitas yang dikenal di dalam aplikasi, misalnya entitas Employee. Contoh entitas lainnya adalah Customer, Product, Order dan sebagainya. Selain dikenal sebagai objek di dalam kode program, entitas ini biasanya dikenal juga sebagai table di dalam database. Dengan demikian, struktur model biasanya tidak jauh berbeda dengan struktur table yang bersangkutan, walaupun strukturnya tidak perlu sama persis (inilah salah satu keunggulan iBATIS dibandingkan Hybernate). 1. Jalankan Eclipse dan buat sebuah package melalui menu New Package. Beri nama sebagai org.exercise01.persist.model. 2. Di dalam package tersebut, buat sebuah class dan beri nama sebagai Employee.java. 3. Salin kode program di bawah ini ke dalam class tersebut. Perhatikan bahwa property dari class ini analogi dengan kolom-kolom di dalam table Employee. Kode program 3. Employee.java. package org.exercise01.persist.model; import java.sql.Timestamp; public class Employee { private int employeeId; private String lastName; private String firstName; private String title; private String titleOfCourtesy; private Timestamp birthDate; private Timestamp hireDate; private String address; private String city; private String region; private String postalCode; private String country; private String homePhone; private String extension; private String notes; public int getEmployeeId() { return employeeId; } public void setEmployeeId(int employeeId) { this.employeeId = employeeId; } public String getLastName() { return lastName; } public void setLastName(String lastName) { this.lastName = lastName; } public String getFirstName() { return firstName; }
-12-
public void setFirstName(String firstName) { this.firstName = firstName; } public String getTitle() { return title; } public void setTitle(String title) { this.title = title; } public String getTitleOfCourtesy() { return titleOfCourtesy; } public void setTitleOfCourtesy(String titleOfCourtesy) { this.titleOfCourtesy = titleOfCourtesy; } public Timestamp getBirthDate() { return birthDate; } public void setBirthDate(Timestamp birthDate) { this.birthDate = birthDate; } public Timestamp getHireDate() { return hireDate; } public void setHireDate(Timestamp hireDate) { this.hireDate = hireDate; } public String getAddress() { return address; } public void setAddress(String address) { this.address = address; } public String getCity() { return city; } public void setCity(String city) { this.city = city; } public String getRegion() { return region; } public void setRegion(String region) { this.region = region; } public String getPostalCode() { return postalCode; } public void setPostalCode(String postalCode) { this.postalCode = postalCode; } public String getCountry() { return country; } public void setCountry(String country) { this.country = country; }
-13-
public String getHomePhone() { return homePhone; } public void setHomePhone(String homePhone) { this.homePhone = homePhone; } public String getExtension() { return extension; } public void setExtension(String extension) { this.extension = extension; } public String getNotes() { return notes; } public void setNotes(String notes) { this.notes = notes; } }
Di dalam class tersebut tidak ada method lain kecuali method getter dan setter untuk setiap property.
-14-
Membuat Pemetaan SQL dari Table dengan Model Bagian ini adalah bagian yang terpenting karena inti dari iBATIS Framework adalah pemetaan SQL (SQL mapping). Ilustrasi mengenai SQL mapping diperlihatkan pada gambar di bawah ini. Perhatikan bagian bawah dari gambar tersebut, tampak bahwa SQL map ada di tengah-tengah antara table-table database dan modelmodel (class Java) sekaligus menjadi acuan dari SqlMapConfig.xml sehingga jelas bahwa SQL map adalah sentral dari semuanya. Itulah sebabnya sebagian besar waktu yang dicurahkan oleh programmer di dalam menggunakan iBATIS framework adalah bekerja dengan SQL map. BUSINESS LOGIC PERSISTENCE LAYER ABSTRACTION LAYER Implementasi
DaoFactory.java
SqlMapConfig.xml
SQL Map
DATA CUSTOMER EMPLOYEE ORDER PRODUCT ...
JDBC
Model
Customer.xml Employee.xml Order. xml Product.xml ...
Ingat bahwa SQL map harus dibuat untuk setiap entitas.
-15-
Sekarang kita lihat bagaimana membuat sebuah SQL map. 1. Jalankan Eclipse dan buat sebuah file XML di dalam package org.exercise01.persist.dao melalui menu New Other, kemudian pilih XML. Beri nama file tersebut sebagai Employee.xml.] 2. Salin kode program di bawah ini ke dalam file XML tersebut dan simpan semua perubahan. Kode program 4. Employee.xml. <sqlMap namespace="Employee"> <select id="getSimpleEmployee" resultClass="org.exercise01.persist.model.Employee"> SELECT EmployeeID AS employeeId ,LastName AS lastName ,FirstName AS firstName ,Title AS title ,TitleOfCourtesy AS titleOfCourtesy ,BirthDate AS birthDate ,HireDate AS hireDate ,Address AS address ,City AS city ,Region AS region ,PostalCode AS postalCode ,Country AS country ,HomePhone AS homePhone ,Extension AS extension FROM Employees
Sekarang kita akan pahami bagian-bagian dari SQL map di atas. Kode program tersebut adalah bentuk SQL map yang paling sederhana karena saat ini fungsinya hanya untuk membaca data dan itu pun menggunakan perintah SELECT dasar yang statis tanpa diikuti kondisi WHERE dan parameter-parameter apapun. Pada tingkat lanjut, SQL map mampu membentuk perintah SQL yang dinamis. Tahap itu akan dibicarakan nanti setelah konsep dasarnya bisa dipahami. Perhatikan bahwa SQL map ini membaca data dari table Employees. Setiap SQL map memiliki sebuah pengenal yang unik atau ID, dalam contoh di atas adalah getSimpleEmployee. Selanjutnya SQL map ini dipetakan dengan sebuah model yang strukturnya bersesuaian, dalam hal ini adalah class Employee yang ada di dalam package org.exercise01.persist.model. Apakah Anda sudah mulai memahami cara kerjanya? Jika di dalam sebuah aplikasi terdapat beberapa entitas, maka SQL mapping harus dibuat untuk setiap entitas tersebut – sebuah SQL map untuk setiap table dan sebuah class.
-16-
Membuat Implementasi Bagian terakhir yang dilakukan di dalam persistence layer adalah membuat implementasi dari SQL map. Perhatikan dari gambar sebelumnya bahwa business logic tidak langsung mengakses SQL map tetapi melalui sebuah implementasi. Artinya sebuah implementasi menjadi kulit terluar atau antar muka bagi business logic untuk berinteraksi dengan persistence layer. 1. Jalankan Eclipse dan buat sebuah package melalui menu New Package. Beri nama sebagai org.exercise01.persist.impl. 2. Di dalam package tersebut, buat sebuah class dan beri nama sebagai EmployeeSimpleImpl.java. 3. Salin kode program di bawah ini ke dalam class tersebut. Kode program 5. EmployeeSimpleImpl.java. package org.exercise01.persist.impl; import import import import
public class EmployeeSimpleImpl { private static EmployeeSimpleImpl instance; private SqlMapClient mapper; public EmployeeSimpleImpl() throws Exception { mapper = DaoFactory.getSqlMapClient(); } public static EmployeeSimpleImpl getInstance() throws Exception { if(instance == null) instance = new EmployeeSimpleImpl(); return instance; } @SuppressWarnings("unchecked") public List<Employee> retrive() throws IllegalArgumentException, Exception { try { return mapper.queryForList("getSimpleEmployee", null); } catch (Exception e) { throw e; } } }
Di dalam class EmployeeSimpleImpl terdapat dua buah method yaitu getInstance untuk mendapatkan referensi sebuah instance dari class yang bersangkutan; dan retrive untuk mendapatkan rangkaian (List) dari objek Employee sebagai hasil eksekusi perintah SELECT melalui pemanggilan SQL map dengan ID getSimpleEmployee. -17-
Tentunya kemampuan sebuah implementasi tidak terbatas hanya untuk membaca data. Ia bisa dikembangkan dengan menambahkan method-method lain misalnya update (untuk UPDATE
), delete (untuk DELETE
), create (untuk INSERT
), execute (untuk EXEC <stored_procedure>) dan sebagainya.
-18-
Memanggil Persistence Layer dari Business Logic Sebagai akhir pembahasan dari bagian ini, akan diperlihatkan kode program dari business logic saat ia berinteraksi dengan persistence layer yang baru saja dibuat tadi. 1. Jalankan Eclipse dan buat sebuah package melalui menu New Package. Beri nama sebagai org.exercise01.persist. 2. Di dalam package tersebut, buat sebuah class dan beri nama sebagai PersistExercise01.java. 3. Salin kode program di bawah ini ke dalam class tersebut. Kode program 5. PersistExercise01.java. package org.exercise01.persist; import java.util.*; import org.exercise01.persist.impl.*; import org.exercise01.persist.model.*; public class PersistExercise01 { /** * @param args */ public static void main(String[] args) { try { EmployeeSimpleImpl impl = new EmployeeSimpleImpl(); List<Employee> listOfEmployee = impl.retrive(); System.out.println("========================================================="); System.out.println("Employee ID First Name Last Name"); System.out.println("========================================================="); for(Iterator<Employee> itOfEmployee = listOfEmployee.iterator(); itOfEmployee.hasNext();) { Employee employee = itOfEmployee.next(); System.out.print(employee.getEmployeeId() + "\t\t"); System.out.print(employee.getFirstName() + "\t\t\t"); System.out.println(employee.getLastName()); } System.out.println("=========================================================");
Inti dari kode program di atas yang berhubungan dengan pemanggilan implementasi dari persistence layer ada pada dua baris berikut ini: ... EmployeeSimpleImpl impl = new EmployeeSimpleImpl(); List<Employee> listOfEmployee = impl.retrive(); ...
Baris-baris baris kode program berikutnya hanyalah untuk menampilkan hasilnya (presentation).. Cukup mudah dipahami, bukan?