
Foto oleh panumas nikhomkhai via Pexels
Transaction adalah sekumpulan operasi database yang diperlakukan sebagai satu unit kerja tunggal: semua operasi tersebut harus berhasil seluruhnya, atau gagal seluruhnya tanpa ada yang tersisa setengah jalan. Konsep ini dijamin oleh empat prinsip yang dikenal sebagai ACID.
ACID adalah singkatan dari Atomicity (semua-atau-tidak-sama-sekali), Consistency (data selalu berpindah dari satu keadaan valid ke keadaan valid lain), Isolation (transaksi yang berjalan bersamaan tidak saling mengganggu), dan Durability (perubahan yang sudah di-commit akan tetap tersimpan meski terjadi kegagalan sistem sesaat setelahnya).
Memahami ACID bukan sekadar teori, karena ia menjelaskan mengapa BEGIN TRANSACTION, COMMIT, dan ROLLBACK ditulis dengan cara tertentu, dan mengapa kesalahan kecil dalam penanganan transaksi bisa berakibat pada data yang tidak konsisten di dunia nyata.
Atomicity: Semua Berhasil atau Semua Gagal
Transfer saldo sebagai contoh klasik atomicity
Consistency: Menjaga Aturan Data Tetap Valid
CHECK constraint sebagai penjaga consistency
Isolation: Transaksi Berjalan Tanpa Saling Mengganggu
Isolation mencegah transaksi lain melihat data belum final
Durability: Data Tersimpan Permanen Setelah Commit
COMMIT menjamin durability lewat transaction log
Savepoint dan Nested Transaction di SQL Server
SAVE TRANSACTION memungkinkan rollback sebagian tanpa membatalkan seluruh transaksi
SAVE TRANSACTION membuat titik tengah (savepoint) di dalam sebuah transaksi yang sedang berjalan, sehingga ROLLBACK TRANSACTION bisa diarahkan ke nama savepoint tersebut untuk membatalkan hanya perubahan yang terjadi setelah savepoint dibuat, tanpa membatalkan keseluruhan transaksi dari awal. Fitur ini berguna ketika sebagian logika di tengah transaksi bersifat opsional atau bergantung pada kondisi yang baru diketahui belakangan.
SQL Server sebenarnya tidak memiliki konsep true nested transaction seperti beberapa RDBMS lain; memanggil BEGIN TRANSACTION berulang kali hanya menaikkan nilai @@TRANCOUNT, dan ROLLBACK TRANSACTION tanpa nama akan selalu membatalkan seluruh rangkaian transaksi hingga level terluar, bukan hanya level BEGIN TRANSACTION terakhir, sehingga pola yang terlihat seperti transaksi bertingkat pada kode aplikasi sebenarnya tetap diatomic sebagai satu transaksi tunggal.
Memahami perbedaan ini penting agar developer tidak salah berasumsi bahwa ROLLBACK di dalam sub-procedure hanya akan membatalkan perubahan procedure tersebut; karena nyatanya rollback tanpa nama savepoint akan membatalkan seluruh transaksi induk, termasuk perubahan yang sudah dilakukan oleh pemanggil sebelum procedure tersebut dipanggil.
Pertumbuhan Transaction Log Akibat Transaksi Panjang
Transaksi yang tidak kunjung commit menahan virtual log file agar tidak bisa dipakai ulang
Setiap operasi yang mengubah data dicatat ke transaction log sebelum perubahan diterapkan ke data file, dan log record tersebut baru bisa ditandai bisa dipakai ulang (truncate) setelah transaksi yang menghasilkannya selesai di-commit dan, pada recovery model FULL, setelah BACKUP LOG dijalankan. Transaksi yang berjalan sangat lama, misalnya memproses jutaan baris dalam satu BEGIN TRANSACTION tunggal, akan menahan seluruh log record sejak transaksi dimulai agar tidak bisa dipakai ulang.
Dampak paling umum dari situasi ini adalah file transaction log bertumbuh sangat cepat karena ruang log lama tidak bisa dipakai ulang selama transaksi masih terbuka, bahkan jika BACKUP LOG dijadwalkan rutin sekalipun, karena backup log tidak bisa membebaskan ruang yang masih dipakai transaksi aktif. Pada kasus ekstrem, log file bisa memenuhi seluruh disk dan menyebabkan database berhenti menerima transaksi baru.
Mitigasi umum adalah memecah operasi besar menjadi batch-batch kecil dengan commit terpisah di setiap batch, misalnya memproses 10000 baris lalu COMMIT sebelum melanjutkan ke batch berikutnya, sehingga ruang log bisa dipakai ulang secara bertahap. DBCC OPENTRAN dan kolom log_reuse_wait_desc pada sys.databases menjadi alat diagnosis utama untuk mengidentifikasi transaksi mana yang menjadi penyebab log tidak kunjung mengecil, sehingga tindakan perbaikan bisa diarahkan ke sesi yang tepat tanpa harus menebak penyebabnya.
Transaksi Terdistribusi Lintas Server dengan MSDTC
BEGIN DISTRIBUTED TRANSACTION dikoordinasikan oleh MSDTC lintas dua server
Transaksi terdistribusi diperlukan ketika satu unit kerja logis harus mengubah data pada lebih dari satu instance SQL Server sekaligus, misalnya melalui linked server, dan seluruh perubahan tersebut harus bersifat atomic yaitu semuanya berhasil commit atau semuanya rollback bersamaan. BEGIN DISTRIBUTED TRANSACTION secara otomatis melibatkan MSDTC begitu pernyataan menyentuh server kedua.
MSDTC berperan sebagai koordinator yang menjalankan protokol two-phase commit, di mana pada fase pertama seluruh server yang terlibat diminta memastikan kesiapan commit, dan hanya setelah semua menyatakan siap barulah fase commit sesungguhnya dijalankan serentak. Layanan MSDTC harus aktif dan dikonfigurasi mengizinkan komunikasi jaringan antar server, karena transaksi akan gagal total jika MSDTC pada salah satu server tidak dapat dihubungi. Transaksi terdistribusi umumnya memiliki overhead dan latensi lebih tinggi dibanding transaksi lokal biasa, sehingga pendekatan ini sebaiknya dipertimbangkan hanya ketika konsistensi atomic lintas server benar-benar diperlukan, bukan sekadar kemudahan arsitektur.
Kesalahan Umum yang Sering Terjadi
Membuka Transaksi Tapi Tidak Pernah Menutupnya
Transaksi yang dibuka dengan BEGIN TRANSACTION namun tidak diakhiri COMMIT atau ROLLBACK karena ada exception yang tidak tertangani akan membuat lock tertahan lama dan memblokir sesi lain yang mencoba mengakses data yang sama.
Mengira Semua Error Otomatis Membatalkan Transaksi
Tidak semua error di SQL Server otomatis melakukan rollback transaksi; beberapa error hanya menghentikan statement yang sedang berjalan sementara transaksi tetap terbuka, sehingga developer harus eksplisit memeriksa ini di dalam TRY-CATCH.
Membuat Transaksi Terlalu Panjang dan Lama
Transaksi yang mencakup terlalu banyak operasi atau menunggu input dari luar (seperti panggilan API eksternal) di tengah transaksi akan menahan lock terlalu lama, meningkatkan risiko deadlock dan menurunkan concurrency secara keseluruhan.
Kapan Pendekatan Ini Tidak Cocok Dipakai
Menjalankan operasi dalam transaksi eksplisit memberi jaminan konsistensi data yang kuat, namun menambah overhead locking dan logging dibanding menjalankan statement individual tanpa transaksi, sehingga transaksi sebaiknya dibuat seringkas mungkin.
Untuk operasi baca-saja yang tidak mengubah data, transaksi eksplisit umumnya tidak diperlukan karena SQL Server secara default sudah membungkus setiap statement tunggal dalam transaksi implisit; transaksi eksplisit paling dibutuhkan ketika beberapa statement harus berhasil atau gagal bersama-sama.
Ringkasan
ACID adalah fondasi yang menjelaskan mengapa transaksi database dirancang seperti sekarang: Atomicity menjamin semua-atau-tidak-sama-sekali, Consistency menjaga aturan data, Isolation mencegah gangguan antar transaksi, dan Durability memastikan data yang sudah commit tidak hilang. Memahami keempatnya membantu menulis kode transaksi yang benar-benar aman, bukan sekadar menambahkan BEGIN TRANSACTION tanpa memahami konsekuensinya.
Seri Belajar SQL Server:
← Sebelumnya: Trigger di SQL Server dan Kapan Digunakan
→ Selanjutnya: Isolation Level dan Locking di SQL Server