noprianto
noprianto
. 12 min read

Java – Koneksi Database MySQL

Bismillah,
MySQL merupakan salah DBMS(Database Management System) yang sangat terkenal di dunia perkodingan. Aplikasi yang kita bangun sepertinya bagai sayur tanpa garam jika tidak bisa melakukan penyimpanan secara permanen, artinya data yang sudah kita simpan sebelumnya dapat dipanggil atau ditampilkan kembali kemudian. Beberapa contoh DBMS(Database Management System) yang lain seperti Oracle, Microsoft Access, PostgreSQL, SQLite, dan yang lainnya. Agar Java dapat berkomunikasi ke database MySQL dibutuhkan sebuah driver yaitu JDBC(Java Database Conectivity).

Contoh kode yang digunakan dalam tulisan ini dibuat menggunakan editor Netbeans 8.2 Java 8 dengan build tool Maven. Kemudian juga menggunakan junit untuk melakukan unit testing, Insya alloh perlengkapan tempur di atas adalah tool familiar yang digunakan oleh programmer java.

Kenapa menggunakan Maven? tidak Ant aja, bawaan Netbeans ketika membuat project Java. Maven merupakan sebuah package manager atau sebuah tool untuk mengorganisasi library, selain itu juga digunakan untuk membungkus aplikasi yang akan kita deploy. Misalnya seperti ini, jika kita menggunakan Maven kita tidak perlu include library yang dibutuhkan sehingga ketika upload ke github akan lebih ringan(ngirit bandwidth). Selanjutnya project yang dibuat menggunakan Maven juga dapat dibuka oleh editor apapun yang support Maven. Semua konfigurasi project Maven terdapat di dalam file pom.xml

Fungsi CRUD MySQL dengan Java

Ya, biasanya ketika akan mencoba teknologi yang baru dalam programming hal yang pertama biasanya adalah membuat aplikasi CRUD(Create, Read, Update, dan Delete). Kenapa demikian karena ketika kita membangun sebuah aplikasi, pasti di dalam aplikasi tersebut ada fitur atau fungsi CRUD.

import com.mysql.cj.jdbc.MysqlDataSource;
import java.sql.Connection;
import java.sql.SQLException;
import java.util.logging.Level;
import java.util.logging.Logger;

public class Koneksi {

    private static Connection connection;

    public static Connection getConnection() {
        if (connection == null) {
            try {
                MysqlDataSource dataSource = new MysqlDataSource();
                dataSource.setUser("root");
                dataSource.setPassword("");
                dataSource.setUrl("jdbc:mysql://localhost:3306/akademik?useLegacyDatetimeCode=false&serverTimezone=UTC");
                connection = dataSource.getConnection();
            } catch (SQLException ex) {
                Logger.getLogger(Koneksi.class.getName()).log(Level.SEVERE, null, ex);
            }
        }
        return connection;
    }

}

Potongan program di atas adalah sebuah class yang berfungsi untuk membangun koneksi ke MySQL, kita deklarasikan interface Connection dengan akses modifier private dan static dan dibuat metode getConnection() untuk mendapatkan koneksi. Di dalam methode tersebut terdapat pengecekan untuk memastikan bahwa koneksi hanya dilakukan sekali ketika aplikasi berjalan, konsep seperti ini sering disebut sebagai singleton. Mengapa singleton? Bayangkan saja misalkan kita punya aplikasi multihreading yang mengakses resource database secara paralel, akibatnya penggunaan CPU akan tinggi dan jika tidak terkontrol aplikasi kita akan mengakibatkan lag. Salah satu cara untuk melakukan setting parameter database koneksi MySQL adalah dengan membuat instance dari objek MysqlDataSource, selanjutnya kita bisa panggil methode set untuk melakukan setting parameter yang kita butuhkan. Contoh di atas yang dilakukan set adalah user, password, dan url.

public class Mahasiswa {
    
    private String nim;
    private String nama;
    private float ipk;
    private String jurusan;

    public Mahasiswa(String nim, String nama, float ipk, String jurusan) {
        this.nim = nim;
        this.nama = nama;
        this.ipk = ipk;
        this.jurusan = jurusan;
    }

    public String getNim() {
        return nim;
    }

    public void setNim(String nim) {
        this.nim = nim;
    }

    public String getNama() {
        return nama;
    }

    public void setNama(String nama) {
        this.nama = nama;
    }

    public float getIpk() {
        return ipk;
    }

    public void setIpk(float ipk) {
        this.ipk = ipk;
    }

    public String getJurusan() {
        return jurusan;
    }

    public void setJurusan(String jurusan) {
        this.jurusan = jurusan;
    }

    @Override
    public String toString() {
        return "Mahasiswa{" + "nim=" + nim + ", nama=" + nama + ", ipk=" + ipk + ", jurusan=" + jurusan + '}';
    }
    
    
}

Rencananya kita akan membuat sebuah tabel yang dimanfaatkan untuk menampung informasi mahasiswa, sehingga kita representasikan ke dalam sebuah class yaitu Mahasiswa. Jika di Java sering disebut dengan entitas atau juga POJO, dimana di dalam class tersebut hanya terdapat getter dan setter. Kenapa hanya terdapat setter dan getter, karena kita tidak diizinkan sembarangan untuk mengubah dan mengambil nilai yang terdapat pada class mahasiswa. Konsep seperti ini sering disebut dengan enkapsulasi.

public interface MahasiswaDao {

    public boolean insert(Mahasiswa m);

    public boolean update(Mahasiswa m);

    public boolean delete(String nim);

    public Mahasiswa getMahasiswaByNim(String nim);

    public List<Mahasiswa> getAllMahasiswa();

}

Selanjutnya kita membuat sebuah DAO, atau kepanjangan dari Data Access Object adalah sebuah interface yang menyediakan fungsi-fungsi pada entitas mahasiswa. Dengan menggunakan DAO ini, kode yang berisi tentang business proses(query ke database) akan dipisahkan secara jelas dan baik.

import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.ArrayList;
import java.util.List;
import java.util.logging.Level;
import java.util.logging.Logger;

/**
 *
 * @author od3ng
 */
public class MahasiswaImpl implements MahasiswaDao {

    private final Connection connection;

    private final String INSERT = "INSERT INTO mahasiswa (nim, nama, ipk, jurusan) "
            + "	VALUES (?,?,?,?)";
    private final String UPDATE = "UPDATE mahasiswa SET nama=?, ipk=?, jurusan=? WHERE nim=?";
    private final String DELETE = "DELETE FROM mahasiswa WHERE nim=?";
    private final String SELECT_ALL = "SELECT nim,nama,ipk,jurusan FROM mahasiswa";
    private final String SELECT_BY_NIM = "SELECT nim,nama,ipk,jurusan FROM mahasiswa WHERE nim=?";

    public MahasiswaImpl(Connection connection) {
        this.connection = connection;
    }

    @Override
    public boolean insert(Mahasiswa m) {
        PreparedStatement prepareStatement = null;
        try {
            prepareStatement = connection.prepareStatement(INSERT);
            prepareStatement.setString(1, m.getNim());
            prepareStatement.setString(2, m.getNama());
            prepareStatement.setFloat(3, m.getIpk());
            prepareStatement.setString(4, m.getJurusan());
            return prepareStatement.executeUpdate() > 0;
        } catch (SQLException ex) {
            Logger.getLogger(MahasiswaImpl.class.getName()).log(Level.SEVERE, null, ex);
        } finally {
            if (prepareStatement != null) {
                try {
                    prepareStatement.close();
                } catch (SQLException ex) {
                    Logger.getLogger(MahasiswaImpl.class.getName()).log(Level.SEVERE, null, ex);
                }
            }
        }
        return false;
    }

    @Override
    public boolean update(Mahasiswa m) {
        PreparedStatement prepareStatement = null;
        try {
            prepareStatement = connection.prepareStatement(UPDATE);
            prepareStatement.setString(1, m.getNama());
            prepareStatement.setFloat(2, m.getIpk());
            prepareStatement.setString(3, m.getJurusan());
            prepareStatement.setString(4, m.getNim());
            return prepareStatement.executeUpdate() > 0;
        } catch (SQLException ex) {
            Logger.getLogger(MahasiswaImpl.class.getName()).log(Level.SEVERE, null, ex);
        } finally {
            if (prepareStatement != null) {
                try {
                    prepareStatement.close();
                } catch (SQLException ex) {
                    Logger.getLogger(MahasiswaImpl.class.getName()).log(Level.SEVERE, null, ex);
                }
            }
        }
        return false;
    }

    @Override
    public boolean delete(String nim) {
        PreparedStatement prepareStatement = null;
        try {
            prepareStatement = connection.prepareStatement(DELETE);
            prepareStatement.setString(1, nim);
            return prepareStatement.executeUpdate() > 0;
        } catch (SQLException ex) {
            Logger.getLogger(MahasiswaImpl.class.getName()).log(Level.SEVERE, null, ex);
        } finally {
            if (prepareStatement != null) {
                try {
                    prepareStatement.close();
                } catch (SQLException ex) {
                    Logger.getLogger(MahasiswaImpl.class.getName()).log(Level.SEVERE, null, ex);
                }
            }
        }
        return false;
    }

    @Override
    public Mahasiswa getMahasiswaByNim(String nim) {
        PreparedStatement prepareStatement = null;
        ResultSet executeQuery = null;
        Mahasiswa m = null;
        try {
            prepareStatement = connection.prepareStatement(SELECT_BY_NIM);
            prepareStatement.setString(1, nim);
            executeQuery = prepareStatement.executeQuery();
            if (executeQuery.next()) {
                System.out.println(""+SELECT_BY_NIM);
                m = new Mahasiswa(executeQuery.getNString("nim"), executeQuery.getString("nama"), executeQuery.getFloat("ipk"), executeQuery.getString("jurusan"));
            }
        } catch (SQLException ex) {
            Logger.getLogger(MahasiswaImpl.class.getName()).log(Level.SEVERE, null, ex);
        } finally {

            try {
                if (prepareStatement != null) {
                    prepareStatement.close();
                }
                if (executeQuery != null) {
                    executeQuery.close();
                }
            } catch (SQLException ex) {
                Logger.getLogger(MahasiswaImpl.class.getName()).log(Level.SEVERE, null, ex);
            }

        }
        return m;
    }

    @Override
    public List<Mahasiswa> getAllMahasiswa() {
        List<Mahasiswa> mahasiswas = new ArrayList<>();
        Statement statement = null;
        ResultSet executeQuery = null;
        try {
            statement = connection.createStatement();
            executeQuery = statement.executeQuery(SELECT_ALL);
            while (executeQuery.next()) {
                Mahasiswa m = new Mahasiswa(executeQuery.getNString("nim"), executeQuery.getString("nama"), executeQuery.getFloat("ipk"), executeQuery.getString("jurusan"));
                mahasiswas.add(m);
            }
        } catch (SQLException ex) {
            Logger.getLogger(MahasiswaImpl.class.getName()).log(Level.SEVERE, null, ex);
        } finally {

            try {
                if (statement != null) {
                    statement.close();
                }
                if (executeQuery != null) {
                    executeQuery.close();
                }
            } catch (SQLException ex) {
                Logger.getLogger(MahasiswaImpl.class.getName()).log(Level.SEVERE, null, ex);
            }

        }
        return mahasiswas;
    }

}

Kode yang sebelumnya adalah sebuah interface dari sebuah DAO, jika ada sebuah interface maka tentunya kita membutuhkan sebuah class untuk mengimplementasikan semua fungsi-fungsi yang terdapat dalam DAO. Kode di atas mengimplementasikan semua operasi-operasi pada mahasiswa.

Jika dilihat dari kode di atas, class yang sering digunakan adalah PrepareStatement, Statement, dan Resultset. Fungsi dari class PrepareStatement dan Statement sebenarnya sama-sama melakukan query ke database, perbedaannya adalah untuk menuliskan query menggunakan PrepareStatement diizinkan menggunakan “?” ketika melewatkan parameter sedangkan Statement biasanya langsung variabel. Sebaiknya menggunakan PrepareStatement jika query tersebut melewatkan sebuah parameter. Resultset sendiri digunakan untuk menampung nilai hasil dari query ke database, jangan lupa ketika setelah melakukan akses ke database untuk melakukan release resource dengan memanggil fungsi close() baik pada PrepareStatement, Statement ataupun Resultset.

public interface MahasiswaService {
    
    public boolean insert(Mahasiswa m);

    public boolean update(Mahasiswa m);

    public boolean delete(String nim);

    public Mahasiswa getMahasiswaByNim(String nim);

    public List<Mahasiswa> getAllMahasiswa();
    
}

Interface di atas saya sebut sebagai service, nama methodenya pun sama dengan yang terdapat pada DAO. Service di sini berfungsi penyedia layanan-layanan yang ada pada mahasiswa, dari sini nanti akan request ke DAO.

public class MahasiswaServiceImpl implements MahasiswaService {

    private final MahasiswaDao mahasiswaDao;

    public MahasiswaServiceImpl(MahasiswaDao mahasiswaDao) {
        this.mahasiswaDao = mahasiswaDao;
    }

    @Override
    public boolean insert(Mahasiswa m) {
        return mahasiswaDao.insert(m);
    }

    @Override
    public boolean update(Mahasiswa m) {
        return mahasiswaDao.update(m);
    }

    @Override
    public boolean delete(String nim) {
        return mahasiswaDao.delete(nim);
    }

    @Override
    public Mahasiswa getMahasiswaByNim(String nim) {
        return mahasiswaDao.getMahasiswaByNim(nim);
    }

    @Override
    public List<Mahasiswa> getAllMahasiswa() {
        return mahasiswaDao.getAllMahasiswa();
    }

}

Seperti biasa, karena service berupa interface kita harus membuat class untuk mengimplementasikannya, dalam hal ini adalah class MahasiswaServiceImpl. Terlihat lebih sederhana kodenya kan dan jauh lebih rapih. 🙂

public class JdbcUtils {

    private static MahasiswaDao mahasiswaDao;

    public static MahasiswaDao getMahasiswaDao() {
        if (mahasiswaDao == null) {
            mahasiswaDao = new MahasiswaImpl(Koneksi.getConnection());
        }
        return mahasiswaDao;
    }

}

Sedangkan class di atas adalah class helper penyedia semua DAO, jadi nanti jika akan ada DAO yang lain silahkan ditambahkan ke class tersebut. Yang terakhir kita bisa menjalankan class-class yang sudah kita buat, sebenarnya sudah bisa dijalankan tetapi akan kita unit test dari salah satu class di atas.

public class AppTest {

    MahasiswaService ms;

    @Before
    public void setUp() {
        ms = new MahasiswaServiceImpl(JdbcUtils.getMahasiswaDao());
    }

    @After
    public void tearDown() {
    }

    @Ignore
    @Test
    public void testInsert() {
        Mahasiswa m = new Mahasiswa("075410200", "Singgih Kuncoro", 2.75F, "Teknik Mesin");
        assertTrue(ms.insert(m));
    }

    @Ignore
    @Test
    public void testUpdate() {
        Mahasiswa m = new Mahasiswa("075410200", "Singgih Kuncoro Aji", 2.80F, "Teknik Mesin");
        assertTrue(ms.update(m));
    }

    @Test
    public void testGetMahasiswaByNim() {
        assertTrue(ms.getMahasiswaByNim("075410099") != null);
    }

    @Ignore
    @Test
    public void testGetAllMahasiswa() {
        assertTrue(ms.getAllMahasiswa().size() > 0);
    }

    @Ignore
    @Test
    public void testDelete() {
        assertTrue(ms.delete("075410200"));
    }

}

Sebenarnya sebuah yang unit test adalah wajib hukumnya sebelum nanti menuju integration test, unit test digunakan untuk mengecek semua bagian-bagian kecil dari program yang Anda bangun apakah outputnya sudah sesuai yang diharapkan. Untuk melakukan hal tersebut digunakan junit jika di java, sebenarnya ada juga namanya mockito. Disana ada beberapa annotation yang digunakan untuk melakukan testing seperti

  • @Test digunakan untuk menandai methode yang akan dilakukan testing
  • @Ignore sebagai penanda bahwa methode tersebut tidak akan dilakukan testing
  • @Before berarti methode yang ada annotation tersebut akan dieksekusi sebelum methode yang ada @Test dieksekusi
  • @After artinya adalah kebalikan dari @Before, setelah methode yang ada @Test dieksekusi.

T E S T S
Running com.odeng.maven.crud.mysql.AppTest
Tests run: 5, Failures: 0, Errors: 0, Skipped: 4, Time elapsed: 1.013 sec
Results :
Tests run: 5, Failures: 0, Errors: 0, Skipped: 4

BUILD SUCCESS

Ketika dijalankan class untuk test yang kita buat, outputnya adalah kira-kira seperti di atas. Berarti nama class tesnt adalah AppTest, @Test ada 5 methode dan yang dilakukan @Ignore 4 methode. Untuk membuat class test, Netbeans juga sudah memfasilitasi dari klik kanan project – New – Other – Piilh kategori – Unit Tests – Test for Existing Class.

Oh ya kemudian dalam project Maven yang paling penting adalah file pom.xml, semua konfigurasi ada di sana. Kira-kira contohnya adalah sebagai berikut

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <groupId>com.odeng</groupId>
    <artifactId>maven-crud-mysql</artifactId>
    <version>1.0-SNAPSHOT</version>
    <packaging>jar</packaging>
    <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <maven.compiler.source>1.8</maven.compiler.source>
        <maven.compiler.target>1.8</maven.compiler.target>
    </properties>
    <dependencies>
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>8.0.16</version>
        </dependency>
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.12</version>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>org.hamcrest</groupId>
            <artifactId>hamcrest-core</artifactId>
            <version>1.3</version>
            <scope>test</scope>
        </dependency>
    </dependencies>
    <build>
        <plugins>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-jar-plugin</artifactId>
                <version>2.3.2</version>
                <configuration>
                    <archive>
                        <manifest>
                            <mainClass>com.odeng.maven.crud.mysql.App</mainClass>
                        </manifest>
                    </archive>
                </configuration>
            </plugin>
        </plugins>
    </build>
</project>

Jika dilihat file pom.xml di atas adalah berisi tentang deskripsi dari sebuah project di beberapa awal baris, depedency atau library yang dibutuhkan pada baris selanjutnya, dan yang terakhir terkait dengan build aplikasi kita. File pom.xml akan dibuatkan secara automatis ketika kita membuat project Maven dengan Netbeans, jadi jangan kwatir untuk membuat secara manual. Silakan clone di github codingan di atas.

Demikianlah artikel saya terkait dengan koneksi database MySQL menggunakan Java, semoga bermanfaat. Saya yakin artikel yang saya tulis masih jauh dari kata sempurna, dimohon saran dan kritiknya. Happy Coding ^_^

comments powered by Disqus