Membuat Aplikasi Database Tanpa Coding Dengan NetBeans

P.S.: Pada artikel ini, saya memakai database Oracle TimesTen, akan tetapi langkah yang sama juga dapat diterapkan pada database lainnya asalkan memilih driver JDBC yang tepat untuk database tersebut.

Saya akan mencoba membuat sebuah program Java sederhana yang mengakses dan melakukan query pada database TimesTen.   Saya akan memakai Java 7 di NetBeans 7.3.   Karena NetBeans menyediakan fitur GUI editor yang lumayan canggih, pada artikel ini saya akan menempuh cara ang drag-n-drop (di balik layar NetBeans tetap memakai JPA!).   Saya tidak perlu mengetik kode program, bahkan satu baris kode program pun tidak perlu.   Seorang teman saya sangat tergila-gila pada fasilitas GUI yang drag-n-drop di NetBeans, membuatnya enggan beralih ke IDE lain.   Saya secara pribadi tidak akan pernah 100% bergantung pada visual editor, karena biasanya akselerasi hanya terasa di awalnya tapi sering kali ribet di kemudian hari 😉   Tapi mungkin ini hanya masalah selera; produktifitas seorang developer akan tinggi bila ‘selera’-nya terpenuhi.

Saya akan mulai dengan membuat sebuah proyek baru.   Untuk itu, saya memilih menu File, New Project….   Pada dialog yang muncul, saya memilih Java, Java Application kemudian men-klik tombol Next.   Saya mengisi nama proyek dengan LatihanTimesTen, kemudian menghilangkan tanda centang pada Create Main Class.   Setelah itu saya menyelesaikan pembuatan proyek baru dengan men-klik tombol Finish.

Sama seperti database lainnya yang berbasis SQL, untuk mengakses TimesTen di Java harus melalui JDBC API.   Btw, JDBC adalah sebuah ukan merupakan sebuah singkatan.   Walaupun demikian, nama JDBC sepertinya agak mirip dengan ODBC (Open Database Connectivity) buatan Microsoft, bahkan sekilas terlihat ada persamaan diantara mereka.   Untuk memakai ODBC, dibutuhkan driver yang disediakan oleh pembuat database.   Begitu juga, untuk memakai JDBC dibutuhkan driver JDBC dalam bentuk file JAR yang disediakan oleh pembuat database.   Pada instalasi saya, lokasi driver ini terletak di C:\TimesTen\tt1122_32\lib.   Untuk Java 7, saya akan memakai file bernama ttjdbc7.jar.   Pada dasarnya file ttjdbc7.jar dan ttjdbc6.jar adalah file yang sama (duplikat)!

Saya akan memakai fasilitas GUI dari NetBeans untuk menjelajahi database.   Tapi sebelumnya saya memastikan terlebih dahulu bahwa TimesTen Data Manager sudah dijalankan.   Untuk itu, saya memberikan perintah ttDaemonAdmin -start. Bagi   yang tidak ingin memakai perintah Command Prompt bisa langsung memerika di Control Panel, Administrative Tools, Services.   Setelah itu, saya juga melakukan koneksi pertama kali ke database melalui ttIsql agar database di-load ke memori sehingga dapat dipakai oleh user lainnya.

Lalu, saya memilih menu Window, Services di NetBeans.   Pada Databases, saya men-klik kanan dan memilih New Connection… seperti yang terlihat pada gambar berikut ini:

Mendaftarkan koneksi baru

Mendaftarkan koneksi baru

Setelah itu, pada Driver, saya memilih New Driver….   Akan muncul dialog New JDBC Driver. Saya mengisinya seperti dengan yang terlihat pada gambar berikut ini:

Mendaftarkan driver JDBC baru

Mendaftarkan driver JDBC baru

Pastikan pada Driver Class, yang dipilih adalah com.timesten.jdbc.TimesTenDriver dan bukan com.timesten.jdbc.TimesTenClientDriver.   Hal ini karena saya melakukan direct connection, bukan client server.

Setelah itu, saya men-klik tombol OK.   Kemudian, saya men-klik tombol Next untuk melanjutkan ke tahap berikutnya.

Saya mengisi dialog Customize Connection seperti pada gambar berikut ini:

Menambahkan informasi koneksi

Menambahkan informasi koneksi

Setelah itu, saya men-klik tombol Next.   Saya membiarkan schema SOLID terpilih (sesuai dengan nama user yang saya berikan) dan langsung men-klik tombol Next.   Saya kemudian mengisi Input connection name dengan TimesTen Database LATIHAN (boleh di-isi dengan nama apa saja), kemudian men-klik tombol Finish.

NetBeans tidak dapat menampilkan daftar tabel untuk database TimesTen, tetapi ia tetap dapat membantu saya dalam mengerjakan perintah SQL.   Saya men-klik kanan nama koneksi TimesTen Database LATIHAN, kemudian memilih menu Execute Command….   Akan muncul sebuah editor baru dimana saya bisa mengerjakan perintah SQL untuk koneksi tersebut, seperti yang terlihat pada gambar berikut ini:

Mengerjakan SQL dari NetBeans

Mengerjakan SQL dari NetBeans

Ok, sekarang saya mendefinisikan sebuah koneksi database.   Saya dapat mulai membuat kode program tanpa perlu ‘mengetik‘ (baca: sihir).   Pada window Projects, saya men-klik kanan Source Packages, kemudian memilih New, JFrame Form… seperti yang diperlihatkan oleh gambar berikut ini:

Membuat JFrame baru

Membuat JFrame baru

Bila menu ini tidak terlihat, saya dapat mencarinya dengan memilih Other….

Pada dialog yang muncul, saya mengisi Class Name dengan ProdukView dan mengisi package dengan com.wordpress.thesolidsnake.view.   Setelah itu, saya men-klik tombol Finish.

Pada visual editor yang muncul, saya men-drag komponen Table ke layar utama seperti yang terlihat pada gambar berikut ini:

Menambahkan komponen tabel

Menambahkan komponen tabel

Kemudian, saya men-klik kanan pada komponen yang baru saja saya tambahkan dan memilih menu paling awal yaitu Table Contents….   Pada kotak dialog Customizer Dialog yang muncul, saya memilih Bound, kemudian men-klik tombol Import Data to Form… seperti yang diperlihatkan oleh gambar berikut ini:

Melakukan binding data dari database

Melakukan binding data dari database

Pada dialog Import Data To Form, saya memilih koneksi database dan tabel seperti yang terlihat pada gambar berikut ini (saya mengandaikan bahwa tabel PRODUK sudah dibuat sebelumnya):

Mengambil informasi dari database

Mengambil informasi dari database

Setelah itu, saya men-klik tombol OK.   NetBeans akan memunculkan pesan menunggu untuk proses importing….   Setelah selesai, Binding Source secara otomatis akan terisi dengan produkList.

Saya akan berpindah ke tab Columns untuk mendefinisikan kolom yang akan ditampilkan.   Saya menambahkan dua buah kolom untuk tabel tersebut, sesuai dengan kolom yang ada di database, seperti yang terlihat pada gambar berikut ini:

Menambahkan kolom untuk tabel

Menambahkan kolom untuk tabel

Setelah itu, saya men-klik tombol Close untuk menutup dialog.

Sekarang, saya akan menjalankan aplikasi dengan men-klik tombol Run Project (atau menekan F6).   Pada dialog Run Project yang muncul, saya memastikan bahwa com.wordpress.thesolidsnake.view.ProdukView terpilih sebagai main class, lalu men-klik tombol OK.   Tabel akan muncul terisi dengan data dari database, seperti yang diperlihatkan oleh gambar berikut ini:

Tampilan program saat dijalankan

Tampilan program saat dijalankan

Sesuai dengan janji saya, tidak ada satu barispun kode program yang saya ketik disini.   Tapi dibalik layar, NetBeans akan memakai JPA untuk mengakses database!   Yup, JPA seperti pada plugin simple-jpa yang saya buat untuk Griffon, bukan plain SQL di JDBC.   Dengan demikian, NetBeans juga menghasilkan kode program yang membuat dan memakai EntityManager.   Bukan hanya itu, NetBeans juga menghasilkan sebuah domain class (atau tepatnya JPA Entity) dengan nama Produk yang sudah lengkap dengan named query, seperti yang diperlihatkan pada gambar berikut ini:

JPA Entity bernama Produk yang dihasilkan NetBeans

JPA Entity bernama Produk yang dihasilkan NetBeans

Kode program yang dihasilkan oleh NetBeans memakai org.jdesktop.swingbinding.JTableBinding untuk melakukan binding. Sebagai perbandingan, pada simple-jpa, binding dilakukan melalui SwingBuilder (bawaan Groovy) dan GlazedLists.   Untuk menentukan ekspresi setiap kolom, NetBeans memakai Expression Language (seperti pada JSP dan JSF).   Sebagai perbandingan, pada simple-jpa, saya memakai Groovy template engine yang menerima seluruh ekspresi Groovy.

Iklan

Mengakses Web Services Dari Aplikasi Java Micro Edition (Mobile)

Artikel ini adalah request dari Erna

Seorang mahasiswi bertanya bagaimana cara mengakses database yang ada di server melalui aplikasi Java Micro Edition (JME) di ponsel.  Salah satu cara yang dapat ditempuh adalah dengan menggunakan web services.  Pada tulisan ini, saya akan memakai WS-* Web Services.  Alternatif lain adalah memakai web service RESTfulyang lebih ringan.

Membuat Web Service dengan Java Di Sisi Server

Web Service akan dijalankan pada komputer server yang terhubung dengan database.   Saya akan menggunakan NetBeans IDE. Langkah pertama adalah memilih menu File, New Project…  Kemudian pilih Java Web, Web Application.  Klik tombol Next. Berikan sebuah nama proyek seperti LatihanWebService, kemudian klik tombol Next.

Pada langkah berikutnya, saya memakai server GlassFish Server 3.1.2 dan versi Java EE 6 Web.  Saya membiarkan context path saya berupa /LatihanWebService.  Karena saya tidak akan memakai framework, maka saya langsung men-klik tombol Finish.

Klik kanan pada nama proyek, kemudian pilih New, Web Service…  Pada Web Service Name, isi dengan AksesDatabase.  Kemudian pada package, isi dengan co.id.jocki.webservice.  Kemudian klik tombol Finish.

Pada nama proyek, akan ada folder Web Services yang didalamnya terdapat node AksesDatabase.  Klik kanan pada AksesDatabase, kemudian pilih Add Operation…  Isi Name dengan lihatIsiTabel, dan isi Return Type dengan java.util.ArrayList<String>.  Klik tombol OK.

Saya akan menambah sebuah operasi lagi.  Untuk itu, saya kembali men-klik kanan pada AksesDatabase, kemudian saya memilih Add Operation…  Kali ini saya mengisi dialog yang muncul sehingga terlihat seperti berikut ini:

Membuat operasi Web Service

Membuat operasi Web Service

Klik tombol OK untuk menutup dialog.

Karena saya akan memakai database MySQL, saya perlu menambahkan MySQL connector terlebih dahulu.  Saya men-klik kanan pada nama proyek (LatihanWebService), lalu memilih Properties.  Kemudian saya memilih Libraries, Add Library…  Pada pilihan yang muncul, saya memilih MySQL JDBC Driver, kemudian saya men-klik tombol Add Library.  Klik tombol OK untuk menutup dialog.

Jika saya men-double klik pada AksesDatabase di Projects, NetBeans akan memunculkan kode program dimana saya bisa menuliskan implementasi.  Saya akan memakai kode program Java 7, sehingga untuk menjalankan program ini dibutuhkan Java JDK minimal versi 7.  Java versi terbaru dapat di-download di http://www.oracle.com/technetwork/java/javase/downloads/index.html.  Selain itu, saya men-klik kanan nama proyek, memilih Properties.  Pada Sources, saya memastikan bahwa JDK 7 sedang dipilih di bagian Source/Binary Format.

Berikut ini adalah isi file AksesDatabase.javayang telah saya modifikasi:

package co.id.jocki.webservice;
import com.mysql.jdbc.jdbc2.optional.MysqlConnectionPoolDataSource;
import java.sql.*;
import java.util.ArrayList;
import javax.jws.WebMethod;
import javax.jws.WebParam;
import javax.jws.WebService;

@WebService(serviceName = "AksesDatabase")
public class AksesDatabase {
  private MysqlConnectionPoolDataSource dataSource;

  public AksesDatabase() {
    dataSource = new MysqlConnectionPoolDataSource();
    dataSource.setUser("jocki");
    dataSource.setPassword("password");
    dataSource.setURL("jdbc:mysql://localhost:3306/latihan"); 
  }

  private void buatTabelBilaBelumAda(Connection cn) throws SQLException {
    ResultSet rs = cn.getMetaData().getTables(null, null, "namatabel", null);
    if (rs.next()==false) {
      // Tidak ada tabel dengan nama 'namatabel', maka buat tabel tersebut
      cn.createStatement().execute("CREATE TABLE namatabel (data VARCHAR(255))");
    }
  }
  @WebMethod(operationName = "lihatIsiTabel")
  public ArrayList<String> lihatIsiTabel() {
    ArrayList<String> lstReturn = new ArrayList<>(); 
    try (Connection cn = dataSource.getConnection()) {
      buatTabelBilaBelumAda(cn);
      Statement stmt = cn.createStatement();
      ResultSet rs = stmt.executeQuery("SELECT data FROM namatabel");
      while (rs.next()) {
        lstReturn.add(rs.getString("data"));
      }
    } catch (Exception ex) {
      System.out.println("Kesalahan [" + ex.getMessage() + "]");
    } 
    return lstReturn;
  }
  @WebMethod(operationName = "tambah")
  public boolean tambah(@WebParam(name = "nilai") String nilai) { 
    try (Connection cn = dataSource.getConnection()) {
      buatTabelBilaBelumAda(cn);
      PreparedStatement ps = cn.prepareStatement("INSERT INTO namatabel VALUES (?)");
      ps.setString(1, nilai);
      ps.executeUpdate();
    } catch (Exception ex) {
      System.out.println("Kesalahan [" + ex.getMessage() + "]");
      return false;
    }
    return true;
  }
}

Pada kode program di atas, saya mengandaikan bahwa nama user MySQL adalah jocki dan password-nya adalah password.  Bila di database tidak ada user lain, bisa juga menggunakan nama user root dan password dikosongkan (“” / string kosong).   Saya juga mengandaikan nama database yang diakses adalah latihan (ini harus sesuai dengan nama database yang ada di MySQL).

Jalankan web services dengan men-klik kanan pada nama proyek LatihanWebService kemudian memilih menu Run.  Jangan matikan server ini karena nanti akan dipanggil oleh aplikasi JME.

Untuk informasi lebih lanjut mengenai bagaimana cara membuat web services atau ingin membuat implementasi web services dalam bahasa lain, baca artikel yang saya tulis di https://thesolidsnake.wordpress.com/2012/07/04/membuat-web-service-soap-dengan-php-dan-memanggilnya-di-client-java/ , https://thesolidsnake.wordpress.com/2012/05/26/memanggil-web-service-dari-server-java-ee-di-client-php/, atau https://thesolidsnake.wordpress.com/2012/07/08/perbandingan-web-service-soap-antara-java-ee-vs-php/ .

Membuat Aplikasi JME Sebagai Client

Saya akan membuat sebuah aplikasi JME dengan memilih menu File, New Project…  Lalu memilih Java ME, Mobile Application.  Pada Project Name, saya memberi nama LatihanClient.  Saya menghilangkan tanda centang di bagian Create Hello Midlet.  Kemudian saya men-klik tombol Next.  Pada Emulator Platform, saya akan memiliki CLDC Oracle Java(TM) Platform Micro Edition SDK 3.0.5.  Lalu pada Device, saya memilih DefaultCldcMsaPhone1.   Saya memastikan Device Configuration bernilai CLDC-1.1 dan Device Profile bernilai MIDP-2.1.  Kemudian saya men-klik Finish untuk membuat proyek tersebut.

Saya membuat sebuah MIDlet baru dengan men-klik kanan pada nama proyek, kemudian memilih New, MIDlet…  Pada MIDlet Name, saya mengisi LatihanMidlet.  Pada Package, saya mengisi co.id.jocki.midlet.  Lalu saya men-klik tombol Finish.

Langkah berikutnya adalah membuat stub untuk web services.  Saya mulai dengan men-klik kanan pada nama proyek, memilih New, Others…  Pada MIDP, saya memilih Java ME Web Service Client dan men-klik tombol Next. Pada langkah Java ME Web Service Client Information, pilih Running Web Service,  isi WSDL URL dengan http://localhost:8080/LatihanWebService/AksesDatabase.    Ini adalah URL web service yang telah saya buat sebelumnya.  Lalu klik tombol Retrieve WSDL.  Jika tidak terjadi kesalahan, NetBeans akan mengisi field yang ada secara otomatis seperti yang terlihat pada gambar berikut ini:

Menambah Stub WS ke Java ME

Menambah Stub WS ke Java ME

Klik tombol Finish untuk selesai.

Sekarang, di proyek JME LatihanClient, akan ada package AksesDatabase yang dibuat secara otomatis.  Yang perlu saya lakukan sekarang adalah menambahkan kode program pada LatihanMiddlet.java yang akan memakai stub tersebut untuk mengakses web services.

Berikut ini adalah isi LatihanMiddlet.javayang telah saya modifikasi:

package co.id.jocki.midlet;

import aksesdatabase.AksesDatabase;
import aksesdatabase.AksesDatabase_Stub;
import java.rmi.RemoteException;
import javax.microedition.lcdui.*;
import javax.microedition.midlet.MIDlet;

public class LatihanMidlet extends MIDlet {

    private List listData;
    private Form frmTambah;
    private TextField txtData;
    private Command cmdSimpan;
    private Command cmdTambah;

    public void startApp() {
        if (listData==null) {            
            listData = new List("Data Di Database", List.EXCLUSIVE);            
            cmdTambah = new Command("Tambah", Command.ITEM, 0);            
            listData.addCommand(cmdTambah);
            listData.setCommandListener(new CommandListener() {

                public void commandAction(Command c, Displayable d) {
                    if (c==cmdTambah) {
                        Display.getDisplay(LatihanMidlet.this).setCurrent(frmTambah);
                    }
                }

            });

            frmTambah = new Form("Akses Database");
            txtData = new TextField("Data", null, 20, TextField.ANY);
            frmTambah.append(txtData);
            cmdSimpan = new Command("Simpan", Command.OK, 0);
            frmTambah.addCommand(cmdSimpan);
            frmTambah.setCommandListener(new CommandListener() {

                public void commandAction(Command c, Displayable d) {
                    if (c==cmdSimpan) {
                        String data = txtData.getString();
                        simpanDataKeDatabase(data);
                        getDataDariDatabase();
                        Display.getDisplay(LatihanMidlet.this).setCurrent(listData);
                    }
                }

            });

        }
        getDataDariDatabase();
        Display.getDisplay(this).setCurrent(listData);
    }        

    private void getDataDariDatabase() {
        AksesDatabase aksesDatabase = new AksesDatabase_Stub();
        listData.deleteAll();
        try {
            String[] data = aksesDatabase.lihatIsiTabel();
            for (int i=0; i<data.length; i++) {
                listData.append(data[i], null);
            }
        } catch (RemoteException ex) {            
            listData.append("Kesalahan Akses Data [" + ex.getMessage() + "]", null);
        }
    }

    private void simpanDataKeDatabase(String data) {
        AksesDatabase aksesDatabase = new AksesDatabase_Stub();
        try {
            aksesDatabase.tambah(data);
        } catch (RemoteException ex) {
            listData.append("Kesalahan Simpan Data [" + ex.getMessage() + "]", null);
        }
    }

    public void pauseApp() {
    }

    public void destroyApp(boolean unconditional) {
    }
}

Sekarang, saya akan mencoba menjalankan aplikasi JME tersebut dengan men-klik icon Run (F6).  Tampilan awal adalah sebuah List yang harusnya berisi isi tabel (saat ini masih kosong karena belum ada data):

Tampilan Awal (Isi Tabel Masih Kosong)

Tampilan Awal (Isi Tabel Masih Kosong)

Pilih menu “Tambah” (dengan left soft key/tombol untuk menu kiri).  Akan muncul frmTambah yang berisi sebuah TextField.  Saya mengisi TextField ini dengan jocki, kemudian memilih menuSimpan:

Menambah Data Baru

Menambah Data Baru

Hal ini akan menyebabkan nilai “jocki” disimpan di tabel database.   Sekarang saat List mengambil data dari tabel di database, ia akan menemukan sebuah data:

Data Diambil Dari Database

Data Diambil Dari Database

Seandainya saya menambah sebuah data baru dengan nilai “keren”, isi List akan terlihat seperti:

Mengambil Data Dari Database

Mengambil Data Dari Database

Bila ingin lebih yakin lagi, silahkan periksa isi tabel di database dan pastikan terdapat dua record dengan nilai “jocki” dan “keren”.

Day 13: Update Batching Di Database Oracle

Learning In HomeOriginal Date: 25 Januari 2009

Untuk mengurangi round trips ke database, aku bisa memakai update batching di sisi aplikasi JDBC. Tanpa batching, setiap statement SQL dikerjakan di sisi client, akan terjadi komunikasi data melalui jaringan dari client ke server dan sebaliknya. Untuk mengurangi beban jaringan, aku dapat mengumpulkan statement-statement yang ada, kemudian mengirimnya dalam satu kali putaran saja. Update batching di Oracle hanya berlaku untuk PreparedStatement.

Untuk mengatur nilai batch, aku memanfaatkan setDefaultExecuteBatch(int) dari object OracleConnection. Selain itu, agar batching dapat berjalan sesuai harapan, aku harus mematikan fitur autocommit, seperti pada contoh kode berikut:


OracleConnection cn = 
  (OracleConnection) 
  ods.getConnection();
cn.setAutoCommit(false);
cn.setDefaultExecuteBatch(10);

Setelah itu, jika kode berikut dikerjakan:


for (int i=0; i<10; i++) {
  ps.setString(1, 
    "TEST" + i);
  ps.setString(2, 
    "TEST" + i);
  ps.setInt(3, i);
  updatedRecord = 
    ps.executeUpdate();
  System.out.println(
   "Updated Record = " + 
     updatedRecord);
}

maka hasilnya adalah:


Updated Record = 0
Updated Record = 0
Updated Record = 0
Updated Record = 0
Updated Record = 0
Updated Record = 0
Updated Record = 0
Updated Record = 0
Updated Record = 0
Updated Record = 10

Terlihat bahwa insert yang sesungguhnya terjadi pada saat aku menyisipkan record kesepuluh, dimana sepuluh record dikirim bersamaan ke database Oracle.

Jika aku tidak ingin menunggu hingga nilai default batch, aku dapat langsung memanggil sendBatch() milik object OraclePreparedStatement. Untuk membatalkan batch, aku dapat memakai method clearBatch() yang juga milik OraclePreparedStatement.

O ya, untuk mengurangi round trips pada query SELECT, aku dapat menggunakan setRowPrefetch(int) milik OracleStatement, atau setDefaultRowPrefetch(int) milik OracleConnection.

Day 12: Latihan Koneksi Database

Learning In HomeOriginal Date: 24 Januari 2009

Berhubung hari ini aku aku mendapat pinjaman notebook, aku mendapat ide untuk mencoba latihan koneksi database dimana salah satu notebook memiliki program Java untuk untuk mengakses database Oracle di notebook yang satunya lagi.

Sebagai langkah pertama, aku mencoba dulu memastikan koneksi peer-to-peer melalui wifi berlangsung dengan lancar. Aku mulai dengan menambahkan item baru di preferred networks, dimana aku memberikan tanda centang untuk pilihan This is a computer-to-computer (ad hoc) network; wireless access points are not used. Setelah memastikan kedua notebook bisa saling ping, aku siap untuk memulai latihan.

Pada notebook yang berperan sebagai server database, aku menyiapkan sebuah program Java sederhana dimana URL untuk koneksi JDBC bisa diatur secara bebas. Setelah memastikan program bisa jalan dengan baik dengan database di localhost, aku meng-install Oracle Client dengan pilihan Instanst Client yang ditujukan untuk deployment di notebook yang berperan sebagai client.

Semuanya terlihat sempurna bagiku, tapi begitu mencoba menjalankan program di client, Java memunculkan error karena ia tidak menemukan listener, padahal aku sudah men-set URL JDBC agar merujuk pada IP notebook yang berperan sebagai server. Aku menghabiskan waktu cukup lama mengotak-atik kedua notebook, dan akhirnya aku menemukan jawabannya di Oracle Net Manager.

Ternyata listener-ku saat ini hanya mendengarkan pada alamat localhost saja. Aku mencoba menambahkan alamat baru untuk didengar oleh listener, yaitu ip yang aku tentukan untuk koneksi wifi, dan sebuah port listener baru. Dengan URL JDBC baru di notebook client yang sesuai dengan port listener baru, akhirnya koneksi ke database-pun berlangsung dengan sukses. Hari ini aku melakukan latihan yang menarik, aku mendapatkan pengalaman baru yang tidak aku alami jika aku tetap di “localhost”.

Day 11: Cached Rowset Di Oracle JDBC

Learning In HomeOriginal Date: 23 Januari 2009

Oracle 10g menyediakan dukungan rowset di library ocrs12.jar. Hari ini aku akan mencoba salah satu implementasi rowset yaitu cached rowset. Rowset ini memungkinkan aku melakukan pengolahan terhadap data tanpa perlu harus selalu memiliki koneksi aktif ke database. Sebagai latihan, aku akan membuat program untuk menyimpan isi tabel ke dalam sebuah file, kemudian menutup koneksi database, terus men-load isi file tersebut, melakukan modifikasi, baru menuliskan perubahan pada database.

Pertama-tama, aku akan membuat sebuah RowSet yang merupakan implementasi dari OracleCachedRowSet. Lalu aku akan menyimpan hasil execute-nya ke sebuah file, dalam hal ini adalah c:\latihan11.dat, seperti yang terlihat di kode berikut ini:


cachedRowset = new 
  OracleCachedRowSet();
cachedRowset.setUrl(
  "jdbc:oracle:oci:@latihan");
cachedRowset.setUsername(
  "jocki");
cachedRowset.setPassword(
  "password");
cachedRowset.setCommand(
  "SELECT l.* FROM latihan l");
cachedRowset.setReadOnly(
  false);
cachedRowset.setConcurrency(
  OracleCachedRowSet.
    CONCUR_UPDATABLE);
cachedRowset.execute();
		
FileOutputStream fos = new 
  FileOutputStream(
   "c:\\latihan11.dat");
ObjectOutputStream oos = 
  new ObjectOutputStream(fos);
oos.writeObject(cachedRowset);
oos.close();
fos.close();

Setelah itu, aku dapat membaca file latihan11.dat untuk mendapatkan RowSet yang berisi isi tabel latihan. Aku bahkan dapat melakukannya tanpa terkoneksi ke database. Contoh kodenya kira-kira seperti berikut ini:


FileInputStream fis = new 
  FileInputStream("c:\\latihan12.dat");
ObjectInputStream ois = new 
  ObjectInputStream(fis);
cachedRowset = (OracleCachedRowSet) 
  ois.readObject();
ois.close();
fis.close();

Seandainya saja aku melakukan perubahan pada RowSet, seperti menambahkan data baris baru:


cachedRowset.moveToInsertRow();			
cachedRowset.updateString(1, "DATA_BARU");
cachedRowset.insertRow();

Perubahan akan disesuaikan di database bila aku memberikan perintah berikut:


cachedRowset.acceptChanges();

Day 10: Memakai Tipe Data Collection Oracle di JDBC

Learning In HomeOriginal Date: 22 Januari 2009

Hari ini aku akan mencoba membuat memakai salah satu tipe data collection Oracle dan mengaksesnya di aplikasi melalui JDBC. Aku mulai dengan membuat sebuah tabel seperti berikut ini:


CREATE OR REPLACE TYPE 
TYP_HOBI AS 
  TABLE OF VARCHAR2(200);
/

CREATE TABLE HOBI_USER (
  NAMA VARCHAR2(200),
  HOBI TYP_HOBI
) NESTED TABLE HOBI STORE AS 
    TBL_HOBI;

Untuk menulis array berisi string ke dalam field hobi, aku menggunakan kode yang seperti berikut ini:


ArrayDescriptor ad = 
  ArrayDescriptor.
    createDescriptor(
     "TYP_HOBI", cn);
			
String[] hobi = { "BELAJAR", 
  "BERMAIN", "NGANGGUR" };
ARRAY arr = new ARRAY(ad, cn, 
  hobi);
			
OraclePreparedStatement ops = 
  (OraclePreparedStatement) cn.
  prepareStatement(
   "INSERT INTO HOBI_USER 
    VALUES (?,?)");
ops.setString(1, "ME");
ops.setARRAY(2, arr);
ops.executeUpdate();

Sementara untuk membaca nilai field hobi menjadi array berisi string, aku menggunakan kode yang seperti berikut ini:


ARRAY arr = ors.getARRAY(1);
String[] str = (String[]) 
  arr.getArray();
			
for (int i=0; i<str.length; i++) {
  System.out.println(
  "Item #" + i + "; Value = " + 
    str[i]);
}

Day 9: Menyimpan Gambar Dalam Database

Learning In HomeOriginal Date: 21 Januari 2009

Hari ini aku akan belajar menggunakan salah satu jenis data LOB, yaitu BLOB, untuk menyimpan file gambar ke dalam database. Di versi Oracle sebelum 10g, batas maksimal sebuah LOB adalah 2^32 byte atau 4 GB. Sementara mulai Oracle 10g, ukuran sebuah LOB tidak terbatas tergantung kemampuan storage.

Untuk bisa menyimpan isi file gambar ke dalam sebuah tabel, aku harus memperoleh locator BLOB-nya terlebih dahulu. Dengan demikian, aku harus membuat sebuah record baru, kemudian men-select record tersebut untuk mendapatkan locator-nya, dan menulis melalui locator yang diperoleh. Ini adalah contohnya:


psInsert.setString(1, idGambar);
psInsert.execute();

psSelect.setString(1, idGambar);
OracleResultSet rs = (OracleResultSet)
  psSelect.executeQuery();
rs.next();

Untuk melakukan select terhadap baris yang mengandung BLOB, aku harus melakukan locking terhadap baris tersebut terlebih dahulu. Itu sebabnya aku memakai SElECT FOR UPDATE seperti ini:


SELECT GAMBAR FROM DATA_GAMBAR
WHERE ID_NO = ? FOR UPDATE

Selain itu, aku juga mematikan modus auto-commit dan melakukan commit secara manual:


cn.setAutoCommit(false);

Berikut ini adalah contoh kode yang memanfaatkan locator dan menulis ke field BLOB melalui stream:


BLOB blob = (BLOB)
  rs.getObject(1);
OutputStream os =
  blob.setBinaryStream(1l);

FileInputStream fis = new
  FileInputStream(fileGambar);

int size = blob.getBufferSize();
byte[] buffer = new byte[size];
int length = -1;
while (
  (length=fis.read(buffer)
  )!=-1) {
  os.write(buffer,0,length);
}

fis.close();
os.close();
cn.commit();

Aku tinggal melakukan hal yang kebalikan dari menulis untuk membaca data BLOB, seperti pada kode berikut:


psSelect.setString(1, idGambar);
OracleResultSet rs = (OracleResultSet) psSelect.executeQuery();
rs.next();

BLOB blob = (BLOB) rs.getObject(1);
InputStream is = blob.getBinaryStream(1l);

Setelah mendapat InputStream, aku bisa memakainya untuk melakukan manipulasi berdasarkan data BLOB yang aku peroleh, misalnya menggunakan ImageIO untuk menerjemahkan data gambar tersebut kemudian menampilkannya di sebuah JPanel.

Selain menyimpan gambar ke dalam database, Oracle Database juga memungkinkan programmer untuk menyimpan locator yang merujuk ke sebuah file di dalam database. Isi dari file tidak disimpan ke dalam database, melainkan tetap menjadi tanggungan dari file system milik OS. Hal ini dapat dicapai dengan tipe data BFILE. Berikut ini adalah contoh sederhana:


CREATE OR REPLACE DIRECTORY
  DIR_GAMBAR AS
'C:\gambar';

CREATE TABLE DATA_GAMBAR_2 (
  ID_GAMBAR VARCHAR2(30),
  LOKASI_GAMBAR BFILE
);

INSERT INTO DATA_GAMBAR_2 VALUES ('GBR1',
  bfilename('DIR_GAMBAR',
            'Fire Power.jpg'));
INSERT INTO DATA_GAMBAR_2 VALUES ('GBR2',
  bfilename('DIR_GAMBAR',
             'Me.jpg'));

Aku memasukkan data ke dalam field BFILE dengan bantuan fungsi BFILENAME yang meminta parameter berupa nama object directory dan nama file dalam directory tersebut. Untuk membaca file dari BFILE, aku menggunakan kode yang seperti berikut ini:


BFILE bfile = rs.getBFILE(1);
if (bfile.fileExists()) {
  bfile.openFile();
  pnlGambar.setImage(
    bfile.getBinaryStream());
  pnlGambar.repaint();
} else {
  System.out.println(
    "File tidak ditemukan!");
}

Day 7: Koneksi JDBC Ke Database Oracle

Learning In HomeOriginal Date: 19 Januari 2009

Oracle menyediakan driver JDBC di folder %ORACLE_HOME%/jdbc/lib. Oracle juga menyediakan library untuk JTA dan JNDI yang sudah diuji bersama Oracle JDBC driver di folder %ORACLE_HOME%/jlib. URL untuk koneksi database berada dalam format seperti berikut ini:


jdbc:oracle:driver_type:[username/password]@database_specifier

Nilai untuk driver_type dapat berupa thin, oci, atau kprb. Nilai database_specifier dapat berupa Oracle Net Connection descriptor, seperti:


(DESCRIPTION=(ADDRESS=(PROTOCOL=TCP)(HOST=localhost)(PORT=1521))(CONNECT_DATA=(SERVICE_NAME=latihan)))

Untuk thin driver, database_specifier juga dapat berupa format berikut ini:


//host_name:port_number/service_name

Ini adalah contoh memulai koneksi dengan menggunakan Oracle Thin Driver (classes12.jar):


OracleDataSource ods = new OracleDataSource();
String url = "jdbc:oracle:thin:@//localhost:1521/
  latihan.localhost";
ods.setUser("jocki");
ods.setPassword("password");
ods.setURL(url);

Connection cn = ods.getConnection();

Untuk melakukan query, aku harus membuat Statement, dan mendapatkan ResultSet dari Statement tersebut, seperti pada contoh kode berikut:


Statement stmt = cn.createStatement();
ResultSet rs = stmt.executeQuery("SELECT VALUE FROM LATIHAN");
while (rs.next()) {
  System.out.println(rs.getString(1));
}

Driver JDBC Oracle juga menyediakan API untuk mengetahui informasi metadata resultset, seperti pada contoh berikut:


OracleResultSet rs = (OracleResultSet)
   stmt.executeQuery("SELECT * FROM LATIHAN");
OracleResultSetMetaData metadata =
   (OracleResultSetMetaData) rs.getMetaData();
int columnCount = metadata.getColumnCount();

for (int i=1; i<=columnCount; i++) {
  System.out.println("Nama Kolom " + i +
     " = " + metadata.getColumnName(i));
  System.out.println("Tipe Kolom " + i +
    " = " + metadata.getColumnTypeName(i));
}

Untuk mengambil nilai kolom yang bertipe object, aku dapat menggunakan STRUCT atau memakai mapping class Java. Untuk memakai STRUCT, aku dapat menggunakan standar JDBC 2.0 java.sql.Struct, atau memakai class oracle.sql.STRUCT dari Oracle dengan fitur tambahan. Contohnya seperti pada kode berikut ini:


OracleResultSet or = (OracleResultSet)
  os.executeQuery("SELECT * FROM TBL_CIF");

while (or.next()) {
  STRUCT struct = (STRUCT) or.getObject(1);
}

Untuk mendapatkan masing-masing atribut dari STRUCT, aku bisa memakai getOracleAttributes(), seperti pada contoh:


Datum[] datum = struct.
  getOracleAttributes();
for (int i=0; i<datum.length; i++) {
  System.out.println(datum[i]);
}

Untuk memakai STRUCT sebagai parameter dari prepared statement, aku harus membuat StructDescriptor terlebih dahulu, seperti pada contoh berikut ini:


StructDescriptor structDesc =
   StructDescriptor.createDescriptor(
      "INDIVIDUAL_CIF", cn);
Object[] attr = {"ID-123", "ACC-123", "solid",
   "snake", new DATE("1985-03-13 00:00:00")};
STRUCT structData = new STRUCT(structDesc,
    cn, attr);

OraclePreparedStatement ops =
  (OraclePreparedStatement) cn.prepareStatement(
   "INSERT INTO TBL_CIF VALUES (?)");
ops.setObject(1,structData);
ops.executeUpdate();