Topik ini menutup modul transaksi dengan SAVEPOINT, penanda di dalam transaksi yang memungkinkan pembatalan parsial tanpa membuang seluruh unit kerja. Bentuknya menjawab kebutuhan transaksi panjang yang berisi beberapa langkah, di mana satu langkah gagal tidak seharusnya menghukum langkah-langkah yang sudah benar.
Blok penyiapan dataset#
# siapkan ulang tabel dan data contoh untuk topik ini
PGOPTIONS='-c client_min_messages=warning' psql -q -U postgres -d perpustakaan <<'SQL'
DROP TABLE IF EXISTS peminjaman, buku, anggota, kategori CASCADE;
CREATE TABLE kategori (id SERIAL PRIMARY KEY, nama TEXT NOT NULL UNIQUE);
CREATE TABLE anggota (id SERIAL PRIMARY KEY, nama TEXT NOT NULL, email TEXT UNIQUE, bergabung DATE NOT NULL, aktif BOOLEAN NOT NULL DEFAULT TRUE);
CREATE TABLE buku (id SERIAL PRIMARY KEY, judul TEXT NOT NULL, penulis TEXT NOT NULL, tahun INTEGER NOT NULL, kategori_id INTEGER REFERENCES kategori(id));
CREATE TABLE peminjaman (id SERIAL PRIMARY KEY, anggota_id INTEGER NOT NULL REFERENCES anggota(id), buku_id INTEGER NOT NULL REFERENCES buku(id), tanggal_pinjam DATE NOT NULL, tanggal_kembali DATE);
INSERT INTO kategori (nama) VALUES ('Pemrograman'), ('Sains'), ('Sejarah'), ('Fiksi'), ('Statistika');
INSERT INTO anggota (nama, email, bergabung, aktif) VALUES ('Ali Rahman', '[email protected]', '2024-01-15', TRUE), ('Budi Santoso', '[email protected]', '2024-03-02', TRUE), ('Citra Kirana', '[email protected]', '2024-05-20', FALSE), ('Dewi Lestari', '[email protected]', '2024-08-11', TRUE), ('Eka Pratama', NULL, '2025-01-30', TRUE);
INSERT INTO buku (judul, penulis, tahun, kategori_id) VALUES ('Dasar Basis Data', 'Sari Wulandari', 2021, 1), ('Jaringan Komputer', 'Ahmad Fauzi', 2019, 1), ('Fisika untuk Pemula', 'Rina Marlina', 2020, 2), ('Kimia Organik', 'Rina Marlina', 2022, 2), ('Sejarah Nusantara', 'Bambang Wijaya', 2018, 3), ('Cerita Kota Lama', 'Nur Aisyah', 2023, 4), ('Statistika Terapan', 'Sari Wulandari', 2022, 5), ('Algoritma dan Struktur Data', 'Ahmad Fauzi', 2021, 1);
INSERT INTO peminjaman (anggota_id, buku_id, tanggal_pinjam, tanggal_kembali) VALUES (1, 1, '2025-03-01', '2025-03-15'), (1, 7, '2025-03-05', '2025-03-20'), (2, 3, '2025-03-10', NULL), (3, 5, '2025-02-20', '2025-03-01'), (2, 1, '2025-04-02', NULL), (4, 6, '2025-04-07', NULL), (5, 8, '2025-04-09', '2025-04-25'), (4, 2, '2025-05-01', NULL);
SQLPembatalan parsial di dalam satu unit#
SAVEPOINT menandai posisi di dalam transaksi, ROLLBACK TO SAVEPOINT membatalkan segala perubahan setelah posisi itu, dan sisanya tetap hidup sampai COMMIT. Blok berikut menyisipkan anggota baru, mencoba pembaruan yang kemudian disadari keliru, lalu membatalkan pembaruannya saja.
# sisipan dipertahankan, pembaruan dibatalkan parsial
psql -U postgres -d perpustakaan <<'SQL'
BEGIN;
INSERT INTO anggota (nama, email, bergabung) VALUES ('Farah Nabila', '[email protected]', '2025-06-01');
SAVEPOINT sebelum_perubahan;
UPDATE anggota SET aktif = FALSE WHERE nama LIKE 'F%';
SELECT nama, aktif FROM anggota WHERE email = '[email protected]';
ROLLBACK TO SAVEPOINT sebelum_perubahan;
SELECT nama, aktif FROM anggota WHERE email = '[email protected]';
COMMIT;
SQLBEGIN
INSERT 0 1
SAVEPOINT
UPDATE 1
nama | aktif
--------------+-------
Farah Nabila | f
(1 row)
ROLLBACK
nama | aktif
--------------+-------
Farah Nabila | t
(1 row)
COMMITPembacaan pertama menunjukkan Farah berstatus nonaktif akibat pembaruan, sedangkan pembacaan kedua setelah ROLLBACK TO menunjukkan statusnya kembali aktif, dan baris penyisipannya tetap ada. COMMIT pada akhirnya menetapkan sisipan tanpa pembaruan yang dibatalkan, dan pola ini menggantikan dua transaksi terpisah yang rapuh terhadap kegagalan di antara keduanya.
Penanda bersarang dan RELEASE#
Savepoint dapat ditumpuk, dan ROLLBACK TO pada penanda luar membatalkan seluruh penanda dalam beserta perubahannya. RELEASE SAVEPOINT menetapkan isi penandanya ke titik penanda di atasnya, sehingga penanda yang sudah melewati tahap berisikonya dilepaskan untuk keringkasan status transaksi.
# penanda bersarang dengan pelepasan tahap dalam
psql -U postgres -d perpustakaan <<'SQL'
BEGIN;
SAVEPOINT tahap_1;
UPDATE anggota SET email = '[email protected]' WHERE id = 1;
RELEASE SAVEPOINT tahap_1;
SAVEPOINT tahap_2;
DELETE FROM anggota WHERE id = 1;
ROLLBACK TO SAVEPOINT tahap_2;
COMMIT;
SELECT nama, email FROM anggota WHERE id = 1;
SQLBEGIN
SAVEPOINT
UPDATE 1
RELEASE
SAVEPOINT
ERROR: update or delete on table "anggota" violates foreign key constraint "peminjaman_anggota_id_fkey" on table "peminjaman"
DETAIL: Key (id)=(1) is still referenced from table "peminjaman".
ROLLBACK
COMMIT
nama | email
------------+------------------------------
Ali Rahman | [email protected]
(1 row)Pembaruan pada tahap_1 ditetapkan melalui RELEASE, percobaan penghapusan pada tahap_2 dibatalkan, dan anggota Ali tetap ada dengan email barunya pada akhir transaksi. Nama penanda yang sama dapat didefinisikan ulang, dan ROLLBACK TO selalu menunjuk definisi terbaru, kebiasaan yang dihindari dengan penamaan yang bermakna per langkah.
Pemulihan per butir pada pemuatan#
Penggunaan yang paling bernilai adalah pemuatan data batch, di mana setiap butir dikelilingi penanda, sehingga butir yang ditolak constraint tidak membatalkan seluruh pemuatan. Pola ini menjadi satu-satunya cara menangkap error dan melanjutkan, karena status transaksi yang batal tidak dapat dilanjutkan tanpa ROLLBACK TO.
# pemuatan batch yang melewati butir yang ditolak
psql -U postgres -d perpustakaan <<'SQL'
BEGIN;
SAVEPOINT butir_1;
INSERT INTO anggota (nama, email, bergabung) VALUES ('Gilang Ramadhan', '[email protected]', '2025-07-15');
RELEASE SAVEPOINT butir_1;
SAVEPOINT butir_2;
INSERT INTO anggota (nama, email, bergabung) VALUES ('Duplikat', '[email protected]', '2025-07-16');
RELEASE SAVEPOINT butir_2;
COMMIT;
SELECT nama FROM anggota WHERE email = '[email protected]';
SQLBEGIN
SAVEPOINT
INSERT 0 1
RELEASE
SAVEPOINT
ERROR: duplicate key value violates unique constraint "anggota_email_key"
DETAIL: Key (email)=([email protected]) already exists.
ERROR: current transaction is aborted, commands ignored until end of transaction block
ROLLBACK
nama
------
(0 rows)Butir kedua ditolak keunikan emailnya, RELEASE atas transaksi yang batal berubah menjadi ROLLBACK TO secara otomatis, dan butir pertama tetap tersimpan. Inilah alasan pola batch menyandingkan SAVEPOINT dan RELEASE untuk setiap butir, dan pemuatan massal sungguhan memakai COPY pada modul manipulasi data dengan strategi yang serupa.
Kesalahan umum#
Kesalahan pertama adalah mengira ROLLBACK TO menghapus penandanya, padahal penandanya tetap hidup dan dapat dirujuk lagi, sedangkan RELEASE-lah yang menghapusnya. Kesalahan kedua adalah nama penanda yang didaur ulang di dalam satu transaksi, sehingga ROLLBACK TO menunjuk definisi terakhir tanpa disadari, dan penamaan per langkah menyelesaikannya.
Kesalahan ketiga adalah mengandalkan savepoint di luar transaksi, padahal penandanya hidup hanya dalam transaksi pembukanya, dan keluar dari transaksi membuang seluruh penandanya. Kesalahan keempat adalah menumpuk ribuan savepoint pada pemuatan besar tanpa RELEASE, karena penandanya menyimpan status transaksi dan biayanya menumpuk, sedangkan pola berpasangan SAVEPOINT dan RELEASE per butir menjaga biayanya tetap.
Pola batch dengan penanda per butir pada akhirnya dibatasi oleh jumlah penandanya sendiri, karena setiap penanda menyimpan status transaksi dan server menetapkan batas maksimum penanda yang hidup. Pemuatan yang benar melepaskan setiap penanda sesudah butirnya selesai, sehingga jumlah yang hidup tetap satu pada setiap saat, dan batas itu tidak pernah tersentuh. Pola ini juga menjernihkan perannya, yaitu penanda untuk jeda bahaya, bukan untuk dibawa menumpuk sepanjang transaksi.
Ringkasan#
- SAVEPOINT menandai posisi transaksi, dan ROLLBACK TO membatalkan perubahan setelah posisi itu tanpa membuang sisanya.
- Penanda dapat ditumpuk, dan RELEASE menetapkan isi penanda ke penanda di atasnya sekaligus menghapusnya.
- Transaksi yang batal dilanjutkan dengan ROLLBACK TO, sehingga pemuatan batch dapat melewati butir yang ditolak.
- Nama penanda yang unik per langkah mencegah kebingungan rujukan, dan pola SAVEPOINT plus RELEASE menjaga biayanya.
Referensi#
- SAVEPOINT — PostgreSQL Documentation — Referensi SAVEPOINT, ROLLBACK TO, dan RELEASE.
- Transactions — PostgreSQL Tutorial — Pengantar transaksi sebagai dasar penandanya.
- Concurrency Control — PostgreSQL Documentation — Bab MVCC yang melandasi perilaku penandanya.