Primary key sintetis menuntut kita mengirim id pada setiap INSERT — dan menghitung nomor berikutnya sendiri adalah resep bencana: dua operator menambah barang bersamaan, keduanya memilih id 7, dan salah satunya ditolak 1062. AUTO_INCREMENT memindahkan tugas penomoran ke server: setiap baris baru menerima angka berturut dari sebuah penghitung internal yang dikelola MySQL. Pada chapter ini kita akan memasang AUTO_INCREMENT pada primary key, membaca nomor yang barusan dibuat lewat LAST_INSERT_ID(), menyaksikan celah (gap) yang muncul saat insert gagal, dan menguji apa yang terjadi bila kita mengirim nilai id secara manual.
Memasang AUTO_INCREMENT pada Primary Key #
Pasangan AUTO_INCREMENT dan PRIMARY KEY adalah pola standar tabel modern. Atribut ini membuat server mengisi kolom id secara otomatis setiap kali baris baru masuk tanpa nilai id:
CREATE DATABASE belajar_auto;
USE belajar_auto;Output yang Dihasilkan:
Query OK, 1 row affected (0.00 sec)
Database changedCREATE TABLE member (
id INT AUTO_INCREMENT PRIMARY KEY,
email VARCHAR(100) NOT NULL UNIQUE,
nama VARCHAR(100) NOT NULL
);Output yang Dihasilkan:
Query OK, 0 rows affected (0.00 sec)Bedah definisinya:
- Baris 2 (
id INT AUTO_INCREMENT PRIMARY KEY): AtributAUTO_INCREMENTmenempel pada kolomidbertipeINT, dan kolom yang sama menjadi primary key. KolomAUTO_INCREMENTdi MySQL wajib berupa bagian dari index — menjadikannya primary key adalah pilihan paling umum. - Baris 3 (
email VARCHAR(100) NOT NULL UNIQUE): Email tetap unik sebagai aturan bisnis, tetapi identitas teknis tetap dipegangid— pemisahan peran yang kita pelajari di chapter UNIQUE.
Dengan penomoran otomatis, INSERT cukup mengirim data bisnisnya saja:
INSERT INTO member (email, nama) VALUES
('[email protected]', 'Budi'),
('[email protected]', 'Siti');
SELECT id, email, nama FROM member ORDER BY id;Output yang Dihasilkan:
Query OK, 2 rows affected (0.00 sec)
Records: 2 Duplicates: 0 Warnings: 0
+----+------------------+------+
| id | email | nama |
+----+------------------+------+
| 1 | [email protected] | Budi |
| 2 | [email protected] | Siti |
+----+------------------+------+
2 rows in set (0.00 sec)Kedua baris mendapat id 1 dan 2 tanpa kita menyebut angka sama sekali. Penghitung internal lalu berpindah ke angka berikutnya, siap dipakai baris berikutnya.
LAST_INSERT_ID #
Aplikasi sering perlu tahu nomor mana yang barusan diberikan server — misalnya untuk mengisi tabel detail yang merujuk baris induk itu. Fungsi LAST_INSERT_ID() menjawabnya dengan mengembalikan nomor terakhir yang dibuat AUTO_INCREMENT pada sesi kita:
INSERT INTO member (email, nama) VALUES ('[email protected]', 'Ani');
SELECT LAST_INSERT_ID() AS id_terakhir;Output yang Dihasilkan:
Query OK, 1 row affected (0.00 sec)
+-------------+
| id_terakhir |
+-------------+
| 3 |
+-------------+
1 row in set (0.00 sec)Fungsi ini mengembalikan nilai yang dibuat oleh statement INSERT terakhir di sesi yang sama, bukan nomor terbesar di tabel — dua koneksi yang menambah baris bersamaan masing-masing menerima nomornya sendiri tanpa saling menimpa. Karena nilainya terikat sesi, LAST_INSERT_ID() harus dibaca pada sesi yang sama dengan INSERT-nya; pada blok di atas keduanya memang berjalan dalam satu sesi.
Celah Saat Insert Gagal #
Penghitung AUTO_INCREMENT tidak pernah mundur. Setiap nilai yang sudah dialokasikan dianggap terpakai, walau baris yang seharusnya memakainya gagal tersimpan. Kita buktikan dengan statement yang ditolak constraint UNIQUE pada email:
-- @error
INSERT INTO member (email, nama) VALUES ('[email protected]', 'Budi Kedua');Output yang Dihasilkan:
Query OK, 0 rows affected (0.00 sec)
ERROR 1062 (23000): Duplicate entry '[email protected]' for key 'member.email'
ByeServer mengalokasikan nomor 4 untuk baris itu, lalu menolak barisnya karena email sudah dipakai — nomor 4 hangus. Baris berikutnya melompat melewatinya:
INSERT INTO member (email, nama) VALUES ('[email protected]', 'Joko');
SELECT id, email, nama FROM member ORDER BY id;Output yang Dihasilkan:
Query OK, 1 row affected (0.00 sec)
+----+------------------+------+
| id | email | nama |
+----+------------------+------+
| 1 | [email protected] | Budi |
| 2 | [email protected] | Siti |
| 3 | [email protected] | Ani |
| 5 | [email protected] | Joko |
+----+------------------+------+
4 rows in set (0.00 sec)Joko menerima id 5, meninggalkan celah di posisi 4. Pola yang sama berlaku untuk rollback transaksi, penghapusan baris, dan restart server: nilai yang terpakai atau teralokasikan tidak digunakan ulang.
Menetapkan Nilai Manual #
AUTO_INCREMENT tidak melarang kita mengirim nilai id sendiri. Statement berikut menyisipkan baris dengan id 100:
INSERT INTO member (id, email, nama) VALUES (100, '[email protected]', 'Rina');
INSERT INTO member (email, nama) VALUES ('[email protected]', 'Wati');
SELECT id, email, nama FROM member ORDER BY id;Output yang Dihasilkan:
Query OK, 1 row affected (0.00 sec)
Query OK, 1 row affected (0.00 sec)
+-----+------------------+------+
| id | email | nama |
+-----+------------------+------+
| 1 | [email protected] | Budi |
| 2 | [email protected] | Siti |
| 3 | [email protected] | Ani |
| 5 | [email protected] | Joko |
| 100 | [email protected] | Rina |
| 101 | [email protected] | Wati |
+-----+------------------+------+
6 rows in set (0.00 sec)Rina tersimpan dengan id 100 persis seperti yang kita kirim. Perilaku penting muncul pada baris Wati: penghitung internal mengintip nilai manual itu, menaikkan dirinya ke 101, dan baris berikutnya tanpa id menerima 101 — perhatikan hasil SELECT yang menampilkan Wati dengan 101. Sifat “mengikuti nilai terbesar” inilah yang membuat penyisipan id manual tetap aman bagi penomoran berikutnya.
Posisi penghitung saat ini juga bisa dibaca dari definisi tabel:
SHOW CREATE TABLE member\GOutput yang Dihasilkan:
*************************** 1. row ***************************
Table: member
Create Table: CREATE TABLE `member` (
`id` int NOT NULL AUTO_INCREMENT,
`email` varchar(100) NOT NULL,
`nama` varchar(100) NOT NULL,
PRIMARY KEY (`id`),
UNIQUE KEY `email` (`email`)
) ENGINE=InnoDB AUTO_INCREMENT=102 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci
1 row in set (0.00 sec)Baris AUTO_INCREMENT=102 menunjukkan angka yang akan dipakai baris berikutnya. Nilai ini terus bergerak seiring insert dan tidak pernah menurun kembali — menghapus baris tidak menurunkannya.
Referensi #
- Using AUTO_INCREMENT — MySQL 8.4 Reference Manual
- CREATE TABLE Statement — MySQL 8.4 Reference Manual
Penomoran id member kini sepenuhnya di tangan server — unik, berurutan naik, dan tahan dari insert bersamaan, walau tidak dijamin rapat. Constraint yang belum kita sentuh adalah validasi isi kolom itu sendiri: bagaimana database menolak harga negatif atau stok minus? Itu pekerjaan CHECK Constraint pada chapter berikutnya. Sebelum itu, kita bereskan database latihan:
DROP DATABASE IF EXISTS belajar_auto;Output yang Dihasilkan:
Query OK, 1 row affected (0.00 sec)Satu tabel member beserta seluruh nomor otomatisnya ikut terbuang.