MENGAKSES DATABASE DENGAN JDBC November 2009 Tingkat: Oleh : Feri Djuandi Pemula Menengah Mahir Pendahuluan Agar sebuah program Java dapat mengakses database, dibutuhkan sebuah antar muka aplikasi yang disebut Java Database Connectivity (JDBC). JDBC driver adalah sebuah komponen yang menjembatani komunikasi antara program Java dengan database dalam hal pengiriman perintah-perintah SQL maupun pengembalian hasil-hasilnya. JDBC sangat serupa dengan ODBC driver yang dikenal pada programprogram di lingkungan Windows yang berfungsi untuk melakukan hal di atas. Pada masa ini ada banyak system database (disebut juga DMBS atau Database Management System) yang beredar di pasaran seperti SQL Server, Oracle, DB-2, MySQL, Postgree dan masih banyak lagi. Setiap DBMS memiliki JDBC driver yang berbeda-beda untuk setiap penggunaannya. Misalnya JDBC driver untuk SQL Server hanya dapat digunakan untuk mengakses DBMS tersebut dan tidak bisa digunakan untuk mengakses database lain (Oracle misalnya) karena protocol komunikasi setiap DBMS berbeda-beda. Umumnya setiap pengembang DBMS menyediakan JDBC driver yang bisa di-download secara gratis oleh penggunanya, namun ada pula pengembang pihak ke-tiga yang membuat sendiri JDBC driver yang berbayar dan menawarkan beberapa kelebihan. Untuk mendapatkan informasi lebih lengkap mengenai JDBC, silakan membaca artikel di situs web: http://en.wikipedia.org/wiki/jdbc_driver. Terlepas dari DBMS dan JDBC driver yang digunakan, umumnya tidak ada banyak perbedaan di dalam sebuah program Java dalam hal penggunaan class-class yang berkaitan dengan operasi database (java.sql.*) karena class-class tersebut bersifat generik dan tidak terkait secara khusus pada DBMS tertentu. Jadi sebuah program Java yang sama dapat dengan mudah dialihkan dari satu DBMS ke DMBS lain dengan memodifikasi parameter koneksinya. Contoh-contoh program yang diperlihatkan pada artikel ini akan menggunakan Ms SQL Server. Untuk JDBC drivernya, penulis menggunakan komponen bernama jtds yang dapat dipakai untuk SQL Server versi 6.5 hingga 2008. JDBC driver untuk SQL Server ini dapat di-download gratis dari situs web: http://jtds.sourceforge.net/ JVA-FD-09003 MENGAKSES DATABASE DENGAN JDBC 1
Setelah driver tersebut berhasil diperoleh, silakan mengikuti langkah-langkah berikut ini untuk mulai membuat sebuah contoh program. 1. Jalankan Eclipse dan buat sebuah project baru. 2. Beri nama project tersebut sebagai db-exercise01. Klik Finish. 3. Buat sebuah Folder di dalam project yang baru dibuat dan beri nama lib. 4. Secara manual dengan menggunakan Windows Explorer, copy file jtds-1.2.4.jar yang didownload sebelumnya ke dalam folder lib yang ada di dalam folder project ini (di dalam folder workspace dari Eclipse). JVA-FD-09003 MENGAKSES DATABASE DENGAN JDBC 2
5. Lakukan konfigurasi pada Build Path untuk mengasosiasikan file JAR tersebut dengan project ini. Pilih tab Libraries dan klik tombol Add External JARs. Pilih file jtds-1.2.4.jar yang di dalam folder lib tadi. JVA-FD-09003 MENGAKSES DATABASE DENGAN JDBC 3
Saat selesai menambahkan library tersebut, struktur project akan tampak seperti gambar di bawah ini. 6. Buat sebuah package dan beri nama sebagai org.exercise01.db. JVA-FD-09003 MENGAKSES DATABASE DENGAN JDBC 4
7. Di dalam package tersebut, buat sebuah class bernama DbConnect. Secara bersamaan tambahkan juga method main ke dalam class tersebut. Klik Finish. Anda telah selesai membuat sebuah project dan class sebagai langkah persiapan. Silakan mengikuti bagian selanjutnya untuk tahap-tahap pembuatan contoh program. JVA-FD-09003 MENGAKSES DATABASE DENGAN JDBC 5
Membuat Koneksi ke Database Hal pertama yang selalu dilakukan pertama kali saat mengakses sebuah database adalah membuat koneksi. Silakan membuka class DbConnect dan tambahkan baris-baris kode hingga seperti di bawah ini. package org.exercise01.db; import java.sql.*; public class DbConnect public static void main(string[] args) final String JDBC_DRIVER = "net.sourceforge.jtds.jdbc.driver"; final String DATABASE_URL = "jdbc:jtds:sqlserver://127.0.0.1/northwind"; Connection connection = null; // manages connection Statement statement = null; // query statement // connect to database and query try Class.forName( JDBC_DRIVER ); // load database driver class // establish connection to database connection = DriverManager.getConnection( DATABASE_URL, "sa", "sql" ); System.out.println("Connection succeeds"); // create Statement for querying database statement = connection.createstatement(); catch ( SQLException sqlexception ) sqlexception.printstacktrace(); System.exit( 1 ); catch ( ClassNotFoundException classnotfound ) classnotfound.printstacktrace(); System.exit( 1 ); finally // ensure statement and connection are closed properly try if (statement!= null) statement.close(); if (connection!= null) connection.close(); catch (SQLException ex) ex.printstacktrace(); System.exit( 1 ); Silakan menjalankan program di atas. Jika tidak ada kesalahan, akan tampak tulisan Connection succeeds muncul pada layar. Program di atas dapat dipahami secara mudah. Konstanta JDBC_DRIVER diisi dengan nama library dari JDBC driver yang digunakan, dalam hal ini adalah jdts. Perhatikan bahwa nama library yang digunakan pada contoh ini adalah khusus untuk jdts. Jika digunakan JDBC driver lain, maka nama library nya tentu akan berbeda pula karena setiap pengembang dapat menetapkan nama library nya sendiri. Agar dapat mengetahui nama library dari JDBC driver yang bersangkutan secara benar, maka dokumentasi yang menyertai driver tersebut harus dibaca baik-baik. Untuk memastikan tidak ada kesalahan di dalam menuliskan nama library, umumnya di dalam program ditambahkan sebaris perintah untuk mem-verifikasi seperti berikut ini: JVA-FD-09003 MENGAKSES DATABASE DENGAN JDBC 6
Class.forName( JDBC_DRIVER ); Konstanta DATABASE_URL berisi parameter koneksi ke database. Setiap DBMS memiliki format-format yang berbeda dalam hal menuliskan parameter ini. Sekali lagi, dokumentasi yang bersangkutan harus dibaca dengan baik. Class java yang digunakan untuk membuat koneksi database adalah java.sql.connection. Itu sebabnya pada awal program terdapat perintah import java.sql.*;. Perintah untuk membuat koneksi itu sendiri terdapat di dalam blok try yaitu pemanggilan fungsi getconnection yang sekaligus menginisiasi sebuah object Connection. connection = DriverManager.getConnection( DATABASE_URL, "sa", "sql" ); Sementara itu baris-baris kode lainnya yang ada di dalam blok catch adalah untuk penanganan error yang mungkin terjadi. Mereka adalah baris-baris kode best practice yang sebaiknya diikuti saja, walaupun programmer bebas untuk memodifikasinya. Menjalankan Perintah SELECT SELECT adalah perintah SQL yang sangat sering digunakan di dalam setiap operasi database. Untuk menjalankan perintah SELECT, ada dua class yang digunakan yaitu: java.sql.statement : untuk mempersiapkan perintah SQL java.sql.resultset : untuk menampung hasil perintah SELECT Penggunaan kedua class tersebut diperlihatkan pada program di bawah ini dengan memodifikasi blok try.... try Class.forName( JDBC_DRIVER ); // load database driver class // establish connection to database connection = DriverManager.getConnection( DATABASE_URL, "sa", "sql" ); // create Statement for querying database statement = connection.createstatement(); // query database ResultSet resultset = statement.executequery( "select EmployeeID,LastName,FirstName,Title from Employees;" ); // process query results ResultSetMetaData metadata = resultset.getmetadata(); int numberofcolumns = metadata.getcolumncount(); System.out.println( "Employee Table of Northwind Database:" ); for ( int i = 1; i <= numberofcolumns; i++ ) System.out.printf( "%-8s\t", metadata.getcolumnname( i ) ); System.out.println(); while ( resultset.next() ) for ( int i = 1; i <= numberofcolumns; i++ ) System.out.printf( "%-8s\t", resultset.getobject( i ) ); JVA-FD-09003 MENGAKSES DATABASE DENGAN JDBC 7
... System.out.println(); Pada program di atas tampak bahwa object Statement dibuat dari sebuah object Connection melalui method createstatement, dengan cara itu setiap perintah SQL diasosiasikan dengan sebuah koneksi database yang aktif. Sementara itu, object ResultSet dibentuk dari object Statement melalui method executequery. Sangat penting untuk memahami hubungan ketiga object ini yang pembentukannya dilakukan secara berurutan. createstatement executequery Connection Statement RecordSet Setelah hasil eksekusi tertampung di dalam object RecordSet, selanjutnya isi kolom-kolom data dapat diperoleh melalui beberapa method berikut ini: RecordSet.getObject: mengambil nilai kolom dalam tipe class Object RecordSet.getDate: mengambil nilai kolom dalam tipe class Date RecordSet.getDouble: mengambil nilai kolom dalam tipe data standar double RecordSet.getFloat: mengambil nilai kolom dalam tipe data standar float RecordSet.getInt: mengambil nilai kolom dalam tipe data standar int RecordSet.getLong: mengambil nilai kolom dalam tipe data standar long RecordSet.getString: mengambil nilai kolom dalam tipe class String Sebagai opsional, object ResultSetMetaData dapat dibentuk dari object RecordSet menggunakan method getmetadata yang tujuannya untuk mendapatkan informasi mengenai metadata dari RecordSet tersebut seperti jumlah kolom, nama-nama kolom, tipe-tipe data kolom dan sebagainya. Menjalankan Perintah INSERT, UPDATE dan DELETE Bila pada perintah SELECT, perintah SQL dijalankan menggunakan method Statement.executeQuery maka pada perintah INSERT, UPDATE dan DELETE, perintah SQL dijalankan menggunakan method Statement.executeUpdate. Method executeupdate mengembalikan nilai bertipe int yang berisi jumlah baris data yang berhasil diproses dengan perintah tersebut. Sangat penting untuk menjalankan perintah executeupdate di dalam blok try agar jika terjadi kesalahan aliran program akan masuk ke dalam blok catch dan langkah penanganan dapat dilakukan atau pesan kesalahan dapat ditampilkan. Lebih Lanjut dengan Isolasi Transaksi Pada saat di dalam sebuah program terdapat beberapa kali pemanggilan method executeupdate perlu dipertimbangkan apakah perintah-perintah SQL itu perlu dipersatukan di dalam sebuah transaksi. Sebuah transaksi merupakan serangkaian perintah-perintah SQL yang dianggap sebagai satu kesatuan. Jika sebuah perintah gagal, maka keseluruhan perintah itu harus dianggap batal bahkan jika kesalahan itu terjadi di tengah rangkaian perintah maka perintah-perintah yang dijalankan sebelumnya juga harus dibatalkan dan seluruh keadaan harus kembali ke kondisi semula sebelum perintah dijalankan. Dengan kata lain, instruksi commit harus ditunda sampai seluruh rangkaian perintah berhasil dijalankan tanpa kesalahan. JVA-FD-09003 MENGAKSES DATABASE DENGAN JDBC 8
Hal tersebut bisa dilakukan dengan melakukan setting pada object Connection. Secara default object Connection memiliki opsi auto-commit yang bernilai TRUE yang artinya perintah commit dijalankan secara otomatis setiap kali perintah manipulasi data dilakukan. Opsi ini harus diubah menjadi FALSE jika skenario transaksi di atas akan diterapkan. Opsi auto-commit dapat diubah melalui method Connection.setAutoCommit seperti yang ditunjukkan di bawah ini. Connection connection = null; try connection = DriverManager.getConnection( DATABASE_URL, "sa", "sql" ); connection.setautocommit(false); statement.executeupdate(insertcommand); statement.executeupdate(updatecommand); statement.executeupdate(deletecommand); connection.commit(); catch ( SQLException sqlexception ) connection.rollback(); sqlexception.printstacktrace(); System.exit( 1 ); Konsekwensi akibat terbentuknya sebuah transaksi adalah terjadinya penguncian atau isolasi (locking atau transaction isolation) pada table-table yang bersangkutan. Isolasi sangat berpengaruh pada lingkungan multi-user dimana beberapa koneksi dapat secara bersamaan berusaha mengakses table yang sama namun pada satu saat hanya sebuah koneksi yang berhasil sementara koneksi-koneksi yang lain harus mengantri menunggu sampai kunci tersebut dilepaskan dan mengakses table tersebut secara bergantian. Isolasi ini jangan dipandang sebagai hal yang buruk tapi merupakan suatu konsekwensi logis untuk memastikan integritas dan konsistensi data (ACID= atomicity, consistency, isolation, durability). Namun di sisi lain isolasi juga akan mempengaruhi unjuk kerja sebuah program dimana program tersebut terkesan lambat oleh karena ada waktu tunggu pada saat beberapa koneksi mengakses sebuah table secara bergantian. Namun kabar baiknya sampai dengan tahap tertentu tingkat isolasi ini masih bisa diatur mulai dari yang lemah (shared-lock) hingga ketat (exclusive-lock). Pada program di atas tampak operasi database diakhiri dengan perintah Connection.commit saat semua transaksi berhasil dijalankan, namun jika terjadi kesalahan pada salah satu perintah SQL maka program akan lompat ke dalam blok catch dimana perintah Connection.rollback dijalankan dan membatalkan semua transaksi ke posisi awal. Inilah cara kerja isolasi transaksi database. JVA-FD-09003 MENGAKSES DATABASE DENGAN JDBC 9
Sebagai informasi tambahan, berikut ini adalah beberapa istilah yang perlu dipahami berkaitan dengan isolasi: dirty read: sebuah transaksi membaca data dari sebuah baris yang telah diubah oleh transaksi lain sekalipun belum di-commit. Dikatakan dirty karena nilai data itu belum final sebab belum di- tadi menjadi tidak commit, jika terjadi kesalahan dan terjadi rollback maka data yang dibacaa valid. phantom read atau repeatable read: di dalam sebuah transaksi terdapatt beberapa kali perintah pembacaan data yang identik namun hasil yang dikembalikan berbeda karena di antara pembacaan itu terdapatt transaksi lain yang menyisipkan data baru. Dikatakan phantom karena data itu tiba-tiba muncul secara misterius. non-repeatable read atau inconsistent analysis: di dalam sebuah transaksi terdapat beberapa kali perintah pembacaan data yang identik namun hasil yang dikembalikan berbeda karena di antara pembacaan itu terdapat transaksi lain yang merubah data yang ada. Tingkat isolasi dapat diatur melalui parameter bertipe int yang dikirim ke dalam pemanggilan method Connection. settransactionisolation setelah perintah Connection.setAutoCommit(false). Parameter tersebut diwakili dengan nilai konstanta sebagai berikut: Tingkat Isolasi dirty reads nonrepeatable reads phantom reads Connection. TRANSACTION_READ_UNCOMMITTED Connection. TRANSACTION_READ_COMMITTED Connection. TRANSACTION_REPEATABLE_READ Connection. TRANSACTION_SERIALIZABLE = diperbolehkan terjadi x = tidak diperbolehkan terjadi Tampak dari table di atas bahwaa isolasi menggunakan TRANSACTION_READ_UNCOMMITTED adalah yang paling lemah, sementara TRANSACTION_SERIALIZABLE adalah yang paling ketat. Jika tingkat isolasi tidak ditetapkan, maka nilai default-nya adalah tergantung dari setiap DBMS karena standar masing- masing DBMS dapat berbeda-beda. Informasi lebih lanjut mengenai isolasi bisa dibaca pada situs web: http://en.wikipedia.org/wiki/acid http://en.wikipedia.org/wiki/isolation_(database_systems) JVA-FD-09003 MENGAKSES DATABASE DENGAN JDBC 10