Episode ini membahas manajemen transaksi dengan Narayana/JTA, propagation behavior dan rollback, optimasi JPA dengan fetch strategy dan caching, serta database migrations dengan Flyway atau Liquibase.

Di episode 6 kalian menyimpan data dengan Panache. Tapi aplikasi produksi membutuhkan lebih dari sekadar CRUD sederhana: operasi multi-tabel yang harus sukses atau gagal bersama-sama, query yang tidak boros, dan skema database yang berevolusi dengan aman.
Episode 10 membahas lapisan lanjutan persistence: manajemen transaksi dengan Narayana/JTA, propagation behavior dan rollback, optimasi JPA dengan fetch strategy dan caching, serta database migrations dengan Flyway atau Liquibase.
Quarkus memakai Narayana sebagai implementasi JTA. Transaksi dimulai dan diakhiri otomatis dengan annotation @Transactional:
import jakarta.transaction.Transactional;
import jakarta.enterprise.context.ApplicationScoped;
import jakarta.inject.Inject;
@ApplicationScoped
public class OrderService {
@Inject
OrderRepository orderRepository;
@Inject
StockRepository stockRepository;
@Transactional
public void buatOrder(Order order) {
orderRepository.persist(order);
stockRepository.kurangiStok(order.itemId, order.qty);
}
}Jika kurangiStok melempar exception, seluruh transaksi di-rollback — order tidak tersimpan dan stok tidak berkurang. @Transactional menjamin atomicity.
Runtime exception memicu rollback otomatis, sedangkan checked exception tidak. Untuk checked exception, atur rollbackOn:
import jakarta.transaction.Transactional;
@Transactional(rollbackOn = CustomBusinessException.class)
public void buatOrder() throws CustomBusinessException {
// jika CustomBusinessException dilempar, transaksi di-rollback
}Atau gunakan dontRollbackOn untuk mengecualikan exception tertentu dari rollback.
JTA di Quarkus mendukung mode propagation pada @Transactional:
REQUIRED: ikut transaksi yang ada atau buat yang baru. Ini default.REQUIRES_NEW: selalu mulai transaksi baru, pause transaksi luar.MANDATORY: wajib sudah ada transaksi, jika tidak error.NEVER: menolak jika sudah ada transaksi.SUPPORTS: ikut transaksi jika ada, jalan tanpa transaksi jika tidak.Contoh: @Transactional(Transactional.TxType.REQUIRES_NEW) berguna untuk menulis log audit yang tetap tersimpan walau operasi utama gagal.
Kalian bisa memicu rollback secara eksplisit dengan TransactionManager: dalam blok catch, panggil tm.setRollbackOnly() lalu lempar kembali exception. Commit di ujung transaksi otomatis menjadi rollback.
Relasi JPA punya mode lazy dan eager. Default @OneToMany adalah lazy — data anak baru dimuat saat diakses. Untuk menghindari N+1 query, gunakan fetch join dengan PanacheQL:
import io.quarkus.hibernate.orm.panache.PanacheRepository;
import jakarta.enterprise.context.ApplicationScoped;
@ApplicationScoped
public class OrderRepository implements PanacheRepository<Order> {
public Order cariDenganItems(Long id) {
return find("select o from Order o "
+ "left join fetch o.items where o.id = ?1", id)
.firstResult();
}
}left join fetch o.items mengambil order beserta item-nya dalam satu query — menghindari ratusan query kecil.
Hibernate mendukung second-level cache untuk entity yang jarang berubah. Aktifkan dengan konfigurasi:
Aktifkan dengan quarkus.hibernate-orm.cache.enabled=true. Untuk data yang sangat statis, cache di level aplikasi dengan @CacheResult(cacheName = "produk") — pemanggilan berulang dengan id sama tidak menyentuh database.
drop-and-create aman hanya di development. Di produksi, perubahan skema harus terkontrol. Flyway dan Liquibase mengelola versi skema database.
Tambahkan dengan ./mvnw quarkus:add-extension -Dextensions=flyway, lalu konfigurasi:
quarkus.flyway.migrate-at-start=true
quarkus.flyway.locations=db/migrationBuat file migrasi di src/main/resources/db/migration:
CREATE TABLE orders (
id BIGINT GENERATED BY DEFAULT AS IDENTITY PRIMARY KEY,
item_id BIGINT NOT NULL,
qty INT NOT NULL
);Nama file mengikuti pola V<n>__<deskripsi>.sql. Saat aplikasi start, Flyway menjalankan migrasi yang belum dieksekusi. Perintah ./mvnw quarkus:add-extension -Dextensions=flyway menambahkan extension-nya.
Jika memilih Liquibase, extension-nya:
Jika memilih Liquibase, tambahkan dengan ./mvnw quarkus:add-extension -Dextensions=liquibase. Keduanya solid. Pilih satu dan konsisten. Prinsip penting: migrasi hanya bisa ditambah, bukan diubah setelah dieksekusi di environment yang sudah ada.
Episode 10 memperkuat lapisan data aplikasi kalian: memahami transaksi Narayana dengan @Transactional, propagation dan kontrol rollback, optimasi JPA dengan fetch strategy dan second-level cache, serta pengelolaan skema database yang aman dengan Flyway atau Liquibase.
Inti yang harus dibawa pulang:
@Transactional membuat operasi atomic dengan rollback otomatis pada runtime exception.rollbackOn dan dontRollbackOn mengontrol perilaku exception.REQUIRES_NEW cocok untuk log audit yang commit terpisah.Di episode 11 selanjutnya kita akan membahas batch jobs dan scheduling — Quarkus Scheduler untuk task terjadwal, membangun batch processing, konfigurasi task executor dan concurrency control, serta monitoring job dan retry handling.