Implementasi CRUD Menggunakan Java Persistance API dan Hibernate ORM

Ichwan Sholihin
6 min readOct 21, 2023

--

Photo by Joshua Sukoff on Unsplash

Halo semua, pada artikel kali ini kita akan membahas salah satu cara implementasi CRUD (Create, Read, Update, Delete) pada Java dan database MySQL menggunakan Spring JPA dan Hibernate ORM.

Bagi yang baru mengenali istilah CRUD, ini adalah operasi dasar dari sebagian besar aplikasi berbasis data dan menyediakan fungsionalitas untuk berinteraksi dengan informasi dalam sistem perangkat lunak. Operasi-operasi ini dapat diimplementasikan dalam aplikasi menggunakan bahasa pemrograman dan teknologi yang sesuai, seperti SQL untuk basis data relasional atau HTTP methods (GET, POST, PUT, DELETE) untuk API web. Sederhananya, CRUD merupakan operasi pengelolaan data dari sistem yang terhubung ke database.

Sementara itu, Spring Data JPA merupakan salah satu Spring Framework yang menyediakan implementasi JPA (Java Persistence API) berbasis Java untuk mengelola data di aplikasi Java. JPA adalah spesifikasi Java untuk manajemen objek-relasional (ORM) yang memungkinkan pengembang menggunakan objek Java secara langsung untuk berinteraksi dengan database dengan dukungan hibernate ORM. Hibernate sendiri adalah sebuah framework ORM (Object-Relational Mapping) yang digunakan dalam pengembangan aplikasi Java untuk mengelola interaksi dengan database. ORM adalah teknik pemetaan objek ke dalam bentuk data yang dapat disimpan dalam database relasional. Dengan menggunakan Hibernate, pengembang dapat menyimpan, mengambil, dan mengelola data objek Java dalam basis data relasional tanpa menulis SQL (Structured Query Language) secara langsung.

Setup Project

Untuk membuat project, Anda dapat menggunakan template dari https://start.spring.io/. Sesuaikan beberapa konfigurasi pada laman start spring yang anda inginkan. Lalu tambahkan beberapa dependencies seperti Spring Data JPA, MySQL Driver dan Lombok untuk generate method di entity (Baca juga: Implementasi Library Lombok untuk Efisiensi Kode di Java). Setelah itu buka project pada IDE yang Anda gunakan.

Di dalam directory src->resource, tambahkan directory baru dengan nama META-INF dan didalam directory tersebut tambahkan juga file persistence.xml untuk menyimpan konfigurasi antara aplikasi spring dengan database MySQL. Berikut isi dari file persistence.xml :

<persistence xmlns="http://java.sun.com/xml/ns/persistence" version="2.0">
<persistence-unit name="JPADB">
<provider>org.hibernate.jpa.HibernatePersistenceProvider</provider>

<properties>
<property name="jakarta.persistence.jdbc.driver" value="com.mysql.cj.jdbc.Driver"/>
<property name="jakarta.persistence.jdbc.url" value="jdbc:mysql://localhost:3306/dbjpa"/>
<property name="jakarta.persistence.jdbc.user" value="root"/>
<property name="jakarta.persistence.jdbc.password" value=""/>
<property name="hibernate.show_sql" value="true"/>
<property name="hibernate.format_sql" value="true"/>
</properties>
</persistence-unit>
</persistence>

Elemen <persistence> adalah elemen root dari file persistence.xml dan menyatakan bahwa ini adalah file persistence config yang mengikuti spesifikasi XML dari Java Persistence API (JPA) versi 2.0.

Kemudian, terdapat elemen <persistence-unit name="JPADB"> yang mendefinisikan persistence unit dengan nama "JPADB" dan nama unit dapat diganti sesuai dengan keinginan Anda. Dalam konteks JPA, sebuah persistence unit adalah kumpulan objek yang berkaitan dengan pengaturan persistence, termasuk konfigurasi koneksi database dan pemetaan objek ke tabel database.

Di dalam <persistence-unit>, terdapat elemen <provider> yang menunjukkan persistence provider yang digunakan. Dalam kasus ini, persistence provider yang dipilih adalah org.hibernate.jpa.HibernatePersistenceProvider, yang menandakan bahwa Hibernate digunakan sebagai implementasi JPA.

Selanjutnya, dalam elemen <properties>, terdapat beberapa properti yang dikonfigurasi:

  • Properti jakarta.persistence.jdbc.driver menentukan driver JDBC yang digunakan (dalam hal ini, com.mysql.cj.jdbc.Driver).
  • Properti jakarta.persistence.jdbc.url menentukan URL koneksi ke database (dalam hal ini, jdbc:mysql://localhost:3306/dbjpa mengarah ke database local MySQL dengan nama dbjpa). Sebaiknya, buat terlebih dahulu sebuah database dengan nama dbjpa lalu registrasikan pada properti ini.
  • Properti jakarta.persistence.jdbc.user menentukan nama pengguna untuk koneksi database (dalam hal ini, root).
  • Properti jakarta.persistence.jdbc.password menentukan kata sandi untuk koneksi database (dalam hal ini, kosong, menandakan bahwa tidak ada kata sandi yang digunakan).
  • Properti hibernate.show_sql dan hibernate.format_sql mengatur apakah Hibernate akan menampilkan pernyataan SQL yang dihasilkan dan apakah SQL tersebut akan diformat untuk kenyamanan membaca.

Dengan konfigurasi ini, aplikasi yang menggunakan file persistence.xml ini dapat menggunakan Hibernate sebagai penyedia JPA untuk berinteraksi dengan database MySQL yang disebutkan dalam properti-properti koneksi.

Setelah menambahkan konfigurasi database pada file persistence.xml selanjutnya buat sebuah class entity pada project. Class Entity di JPA merupakan representasi dari sebuah table di database SQL. Berikut class entity yang sudah tambahkan:

@Data
@NoArgsConstructor
@Entity
@Table(name = "customers")
public class Customer {

@Id
private String id;

private String name;

@Column(name = "primary_email")
private String primaryEmail;

private Boolean married;

}

Pada class Customer.java terdapat annotation @Data dan @NoArgsConstructor , dua annotation tersebut merupakan fitur dari Lombok library, (pastikan Anda sudah menambahkan Lombok library pada file pom.xml) yang mana annotation @Data merupakan generated annotation untuk method setter-getter, toString() dll tanpa perlu membuat setter-getter untuk seluruh field yang ditambahkan. Untuk annotation @NoArgsConstructor digunakan untuk men-generated sebuah constructor kosong. Annotation @Entity menunjukkan bahwa kelas ini adalah sebuah entitas yang akan disimpan dalam database berupa table. Sedangkan @Table(name = "customers") menginformasikan bahwa entity ini akan disimpan dalam tabel bernama "customers" dalam database.

Tambahkan juga table dengan nama customers pada database local yang sudah Anda registrasikan pada file persistence.xml

CREATE TABLE customers (
id VARCHAR(255) PRIMARY KEY,
name VARCHAR(255),
primary_email VARCHAR(255),
married BOOLEAN
);

Selanjutnya kita dapat mengimplementasikan langsung operasi CRUD. Disini saya akan mengimplementasikan operasi CRUD menggunakan unit test. Buatlah sebuah class unit test dengan nama CrudTest.java

class CrudTest{

private EntityManagerFactory entityManagerFactory;

@BeforeEach
void setUp() {
entityManagerFactory = JpaUtil.getEntityManagerFactory();
}
}

Pertama, deklarasi private EntityManagerFactory entityManagerFactory; mendefinisikan variabel entityManagerFactory sebagai objek EntityManagerFactory. EntityManagerFactory adalah antarmuka dalam JPA yang bertanggung jawab untuk membuat objek EntityManager. EntityManager digunakan untuk berkomunikasi dengan basis data, termasuk operasi-insert, read, update, dan delete (CRUD).

Selanjutnya, menggunakan anotasi @BeforeEach, metode setUp() dijalankan sebelum setiap pengujian dimulai. Dalam metode ini, entityManagerFactory diinisialisasi dengan menggunakan metode JpaUtil.getEntityManagerFactory(). Fungsi dari setUp() adalah untuk mempersiapkan lingkungan pengujian dengan menginisialisasi objek EntityManagerFactory sebelum setiap pengujian dijalankan.

Berikut isi class dari JpaUtil.java

public class JpaUtil {

private static EntityManagerFactory entityManagerFactory = null;

/**
* jika entityManagerFactory null, maka buat entity melalui file persistence.xml,
* jika sudah ada, maka balikan nilai entityManagerFactory.
*/
public static EntityManagerFactory getEntityManagerFactory(){
if (entityManagerFactory == null){
entityManagerFactory = Persistence.createEntityManagerFactory("JPADB");
}

return entityManagerFactory;
}
}

Pada kelas JpaUtil, terdapat sebuah variabel statis entityManagerFactory yang bertipe EntityManagerFactory. Variabel ini diset sebagai static, artinya hanya ada satu salinan dari variabel ini untuk seluruh instansi kelas JpaUtil yang ada dalam aplikasi. Hal ini memastikan bahwa entityManagerFactory tetap konsisten di seluruh aplikasi dan menghindari pembuatan objek EntityManagerFactory yang berlebihan. kelas JpaUtil memastikan bahwa hanya satu objek EntityManagerFactory yang dibuat, meminimalkan overhead dan memastikan konsistensi dalam penggunaan objek EntityManagerFactory di seluruh aplikasi. Utilitas ini memudahkan pengelolaan objek EntityManagerFactory dan memastikan koneksi yang efisien dan andal ke basis data saat berinteraksi dengan JPA.

Untuk implementasi operasi menggunakan CRUD, buatlah sebuah class unit test dengan nama CrudTest.java dan tambahkan kode berikut.

class CrudTest{

private EntityManagerFactory entityManagerFactory;

@BeforeEach
void setUp() {
entityManagerFactory = JpaUtil.getEntityManagerFactory();
}

}

Di dalam kelas ini, terdapat satu atribut privat bernama entityManagerFactory yang merupakan instance dari kelas EntityManagerFactory. EntityManagerFactory adalah bagian dari Java Persistence API (JPA) yang digunakan untuk mengelola entitas dan koneksi ke basis data.

Kemudian, terdapat sebuah method setUp(). Method ini dianotasi dengan @BeforeEach, yang menandakan bahwa akan dijalankan sebelum setiap pengujian (test) dilakukan. Di dalam method setUp(), instance dari EntityManagerFactory diinisialisasi menggunakan method JpaUtil.getEntityManagerFactory() yang sebelumnya sudah ditambahkan. Dapat diasumsikan bahwa method ini mengembalikan instance yang sesuai dari EntityManagerFactory yang diperlukan untuk melakukan pengujian terhadap operasi-operasi CRUD (Create, Read, Update, Delete) pada basis data.

Lalu, tambahkan method insertData() untuk menambahkan data

    @Test
void insertData() {
EntityManager entityManager = entityManagerFactory.createEntityManager();
EntityTransaction entityTransaction = entityManager.getTransaction();
entityTransaction.begin();

Customer customer = new Customer();
customer.setId("1");
customer.setName("Ujang");
customer.setPrimaryEmail("ujang@test.com");
customer.setMarried(true);

Assertions.assertNotNull(customer);
entityManager.persist(customer);

entityTransaction.commit();
entityManager.close();
}

Di dalam method insertData(), pertama-tama, sebuah objek EntityManager dibuat dengan menggunakan entityManagerFactory.createEntityManager(). EntityManager adalah komponen utama dalam JPA yang digunakan untuk berinteraksi dengan basis data. Setelah itu, objek EntityTransaction diperoleh dari EntityManager dengan memanggil entityManager.getTransaction(). EntityTransaction digunakan untuk memulai dan mengelola transaksi dengan basis data.

Setelah transaksi dimulai dengan memanggil entityTransaction.begin(), sebuah objek Customer dibuat. Atribut-atribut objek Customer seperti id, name, primaryEmail, dan married diinisialisasi dengan nilai-nilai tertentu. Selanjutnya, dilakukan pengujian dengan memastikan bahwa objek customer tidak bernilai null menggunakan Assertions.assertNotNull(customer). Jika objek customer tidak null, artinya objek tersebut telah berhasil dibuat dan diinisialisasi dengan nilai-nilai yang benar.

Kemudian, objek customer disimpan (inserted) ke dalam basis data menggunakan metode entityManager.persist(customer). Setelah itu, transaksi diakhiri dengan memanggil entityTransaction.commit(), yang mengonfirmasi bahwa perubahan yang dilakukan dalam transaksi harus disimpan ke dalam basis data. Terakhir, objek EntityManager ditutup dengan memanggil entityManager.close(), yang menutup sesi penggunaan EntityManager dan mengakhiri koneksi ke basis data. Dengan demikian, metode insertData() ini menguji operasi insert data ke basis data untuk objek pelanggan (Customer). Jika operasi ini berhasil tanpa kesalahan, pengujian dianggap berhasil.

Sama halnya dengan method insert, berikut beberapa operasi CRUD yang lain yang dapat Anda coba:

    @Test
void findData() {
EntityManager entityManager = entityManagerFactory.createEntityManager();
EntityTransaction entityTransaction = entityManager.getTransaction();
entityTransaction.begin();

Customer customer = entityManager.find(Customer.class, "1");
Assertions.assertNotNull(customer);
Assertions.assertEquals("1", customer.getId());
Assertions.assertEquals("Ujang", customer.getName());

entityTransaction.commit();
entityManager.close();
}

@Test
void updateData() {
EntityManager entityManager = entityManagerFactory.createEntityManager();
EntityTransaction entityTransaction = entityManager.getTransaction();
entityTransaction.begin();

Customer customer = entityManager.find(Customer.class, "1");
customer.setName("Abdul");
entityManager.merge(customer);

Assertions.assertEquals("1", customer.getId());
Assertions.assertEquals("Abdul", customer.getName());

entityTransaction.commit();
entityManager.close();
}

@Test
void deleteData() {
EntityManager entityManager = entityManagerFactory.createEntityManager();
EntityTransaction entityTransaction = entityManager.getTransaction();
entityTransaction.begin();

Customer customer = entityManager.find(Customer.class, "1");
entityManager.remove(customer);

entityTransaction.commit();
entityManager.close();
}

Perbedaannya hanya terletak pada method yg digunakan pada setiap operasi. Pada hibernate, operasi insert menggunakan method persist(), untuk get data, gunakan method find() , method merge() untuk update dan remove() untuk delete. Namun, pada hibernate diharuskan untuk menggunakan method find() terlebih dahulu pada operasi update dan delete sebagai validasi apakah data tersedia atau tidak.

--

--