Azis Hapidin
Mengenal Database Transaction

Bayangkan ada bagian aplikasi yang mempunyai flow seperti ini:

Sekilas tidak ada yang aneh dengan proses diatas, jika tidak ada masalah maka semua akan baik-baik saja. Tapi bayangkan apa yang akan terjadi jika pada flow diatas terjadi error (error coding/query, hardware, atau masalah lainnya) pada step ketiga, sedangkan step pertama dan kedua sudah terlanjur tereksekusi? Yang terjadi adalah stok produk dan saldo pembeli sudah berkurang sedangkan saldo merchant belum bertambah, tentunya hal seperti ini akan menjadi masalah serius pada aplikasi kita.

Solusinya bagaimana? Yaitu menggunakan Database Transaction, Dengan menggunakan Database Transaction maka kita akan memasukan ketiga query diatas kedalam satu blok dan DBMS akan menganggap ketiga query tadi menjadi suatu kesatuan, sehingga jika terjadi error pada salah satu query maka sistem akan membatalkan (rollback) query yang sudah di eksekusi sebelumnya. Konsep ini adalah pengertian dari Atomic yaitu do all or nothing (lakukan semua atau tidak sama sekali).

Begin, Commit, Rollback

Dalam implementasinya, kita akan bertemu dengan 3 istilah berikut:

BEGIN/START TRANSACTION: adalah perintah untuk memulai sesi database transaction.

COMMIT : adalah perintah untuk menyimpan semua perubahan pada database secara permanen, commit ini dijalankan setelah semua query dieksekusi dan tidak ada error sama sekali.

ROLLBACK: adalah perintah untuk membatalkan semua perubahan data, rollback ini akan dijalankan ketika ada salah satu query yang error. Jika kita menggunakan try..catch, maka perintah rollback ini biasa disimpan di blok catch.

Mengenal ACID

ACID merupakan singkatan dari Atomic, Consistency, Isolation dan Durability. Merupakan sifat yang harus dimiliki database untuk menjamin transaksi reliable (bisa diandalkan).

Atomic

Atomic artinya semua query harus dianggap sebagai satu kesatuan, dalam bagian ini kita mengenal istilah do all or nothing (lakukan semua atau tidak sama sekali).

Consistency

Consistency ini berkaitan dengan Integrity Constraints, jika ada masalah Integrity Constraints maka sistem akan otomatis me-rollback transaksi.

Misal pada table transactions ada field product_id yang merupakan Foreign Key ke id pada table products. Maka jika kita melakukan insert ke table transactions dan memasukan product_id yang tidak ada pada table products maka DBMS akan otomatis me-rollback transaksi. Hal ini berlaku juga untuk Integrity Constraints lain seperti not null field, unique field, dll.

Isolation

Isolation berarti memastikan semua proses yang belum selesai (belum di commit) tidak akan bisa di akses pada sesi lain.

Misal user A melakukan import 100 ribu data ke table transactions, jika user B membaca table transactions maka data yang sedang di import tadi harusnya tidak muncul karena belum di Commit. Begitupun jika user A melakukan operasi UPDATE atau DELETE, sebelum transaksi selesai maka sesi lain tidak akan bisa melihat perubahan tersebut.

Kasus diatas akan terjadi jika Programmer melakukan Commit setelah semua data tersebut selesai di import, akan berbeda ceritanya jika sang Programmer melakukan Commit per 1 data.

Durability

Detelah transaksi selesai (sudah di commit) maka data harus benar-benar disimpan, misal setelah transaction di Commit kemudian terjadi hardware failure (server mati listrik, hardware error) maka data harus sudah tersimpan di database.

Implementasi Database Transaction

Implementasi pada MySQL

Pada MySQL untuk memulai Transaction kita bisa menggunakan perintah START TRANSACTION atau bisa juga dengan BEGIN, tapi pada contoh disini kita akan menggunakan BEGIN.

Contoh Rollback

Pada contoh dibawah kita akan mencoba untuk update stock Sampo Kelir menjadi 9, kemudian kita rollback agar stock Sampo Kelir kembali seperti semula menjadi 10.

mysql> select * from products;

+----+---------------+-------+

| id | name          | stock |

+----+---------------+-------+

|  1 | Sampo Kelir   |    10 |

|  2 | Sampo Pentin  |    20 |

|  3 | Wafer Bembeng |    20 |

+----+---------------+-------+

3 rows in set (0.00 sec)

mysql> BEGIN;

Query OK, 0 rows affected (0.00 sec)

mysql> update products SET stock = 9 WHERE id = 1;

Query OK, 1 row affected (0.02 sec)

Rows matched: 1  Changed: 1  Warnings: 0

mysql> select * from products;

+----+---------------+-------+

| id | name          | stock |

+----+---------------+-------+

|  1 | Sampo Kelir   |     9 |

|  2 | Sampo Pentin  |    20 |

|  3 | Wafer Bembeng |    20 |

+----+---------------+-------+

3 rows in set (0.00 sec)

mysql> ROLLBACK;

Query OK, 0 rows affected (0.01 sec)

mysql> select * from products;

+----+---------------+-------+

| id | name          | stock |

+----+---------------+-------+

|  1 | Sampo Kelir   |    10 |

|  2 | Sampo Pentin  |    20 |

|  3 | Wafer Bembeng |    20 |

+----+---------------+-------+

3 rows in set (0.00 sec)

Contoh Commit

Pada contoh dibawah kita akan melakukan perubahan stok pada salah satu produk, kemudian melakukan Commit.

mysql> select * from products;

+----+---------------+-------+

| id | name          | stock |

+----+---------------+-------+

|  1 | Sampo Kelir   |    10 |

|  2 | Sampo Pentin  |    20 |

|  3 | Wafer Bembeng |    20 |

+----+---------------+-------+

3 rows in set (0.06 sec)

mysql> BEGIN;

Query OK, 0 rows affected (0.01 sec)

mysql> update products SET stock = 4 WHERE id = 3;

Query OK, 1 row affected (0.03 sec)

Rows matched: 1  Changed: 1  Warnings: 0

mysql> COMMIT;

Query OK, 0 rows affected (0.01 sec)

mysql> select * from products;

+----+---------------+-------+

| id | name          | stock |

+----+---------------+-------+

|  1 | Sampo Kelir   |    10 |

|  2 | Sampo Pentin  |    20 |

|  3 | Wafer Bembeng |     4 |

+----+---------------+-------+

3 rows in set (0.00 sec)

Implementasi pada PHP + MySQL

Berikut ini contoh penggunaan Database Transaction jika kita menggunakan PDO (PHP Data Object) menggunakan try..catch:

<?php
 
try {
    // BEGIN/START TRANSACTION
    $db->beginTransaction();
    
    // Jalankan semua query + logic business yang kita butuhkan
    $db->query('Query pertama');
    $db->query('Query kedua');
    $db->query('Query ketiga');
    
    // Jika runtime execution sudah sampai sini, artinya tidak ada error sama sekali
    // Artinya kita sudah bisa melakukan COMMIT
    $db->commit();
} catch (\Throwable $e) {
    // Jika ternyata ada Exception (apapun itu)
    // Maka kita harus melakukan ROLLBACK
    $db->rollback();
    
    throw $e;
}

Pada contoh diatas Rollback dijalankan pada catch (ketika ada exception). Jika memang dibutuhkan, kita juga bisa menyimpan rollback tersebut dalam block pengkondisian (if).

[Bonus] Implementasi pada Laravel

Untuk menggunakan Database Transaction pada Laravel kita cukup memasukan semua perintah pada closure \DB::transaction(), contohnya seperti ini:

<?php
 
DB::transaction(function() use($wallet, $destination, $amount) { {
    $wallet->transferTo($destination, $amount);
});
 

Referensi: