Ranjau bab sebelumnya sudah kita lewati; kini tiba giliran runtime yang paling banyak dipakai untuk API JSON: Node.js. Filosofi Node.js berbeda dari Python dan PHP — semua operasi I/O berjalan asinkron di atas event loop tunggal, sehingga menunggu balasan server MySQL tidak boleh memblokir request lain. Bahasa kuncinya adalah Promise dan await, dan seperti bab Python sebelumnya, contoh kita benar-benar dieksekusi: driver mysql2 sudah terpasang di lingkungan latihan. Kita akan menulis contoh.js lengkap, menjalankannya lewat terminal, membedahnya baris per baris, lalu membandingkan dua gaya API yang hidup berdampingan di ekosistem Node.js: callback klasik dan promise modern.
Driver mysql2 #
Dua nama akan kita jumpai saat mencari driver MySQL untuk Node.js. Paket mysql adalah driver legendaris dari era awal Node.js, sedangkan mysql2 adalah fork yang kini lebih aktif diurus, lebih cepat, mendukung prepared statement dan API Promise bawaan — dan API-nya sengaja dibuat kompatibel sehingga migrasi antar keduanya nyaris tanpa ubahan. Ekosistem nyata (Sequelize, Prisma, dan framework lain) memakai mysql2 di lapisan bawahnya. Kita memilih yang kedua:
npm install mysql2Menyiapkan Data Latihan #
Program kita membaca tabel produk dari database belajar_app. Skemanya dibangun dulu lewat klien mysql supaya chapter ini mandiri:
DROP DATABASE IF EXISTS belajar_app;
CREATE DATABASE belajar_app;
USE belajar_app;
CREATE TABLE produk (
id INT PRIMARY KEY,
nama VARCHAR(100) NOT NULL,
harga INT NOT NULL
);
INSERT INTO produk (id, nama, harga) VALUES
(1, 'Kopi Toraja', 52000),
(2, 'Teh Melati', 28000),
(3, 'Gula Aren', 32000);Satu File Lengkap: contoh.js #
Berikut isi lengkap contoh.js — file ini tersimpan di dalam bundle chapter (bagian Berkas Sumber di akhir halaman) dan siap dijalankan:
// contoh.js — akses MySQL dari Node.js dengan mysql2 (promise API).
// Jalankan dari folder chapter: node contoh.js
// Port default 3306; timpa lewat variabel lingkungan DB_PORT
// bila server MySQL Anda berjalan di port lain.
const mysql = require('mysql2/promise');
async function main() {
const koneksi = await mysql.createConnection({
host: '127.0.0.1',
port: Number(process.env.DB_PORT || 3306),
user: 'root',
password: '',
database: 'belajar_app',
});
const [rows] = await koneksi.query(
'SELECT id, nama, harga FROM produk ORDER BY id'
);
console.log('Daftar produk:');
rows.forEach((r) => console.log(` ${r.id} | ${r.nama} | ${r.harga}`));
const [murah] = await koneksi.query(
'SELECT id, nama FROM produk WHERE harga < ? ORDER BY id',
[40000]
);
console.log('Produk di bawah 40000:');
murah.forEach((r) => console.log(` ${r.id} | ${r.nama}`));
await koneksi.end();
console.log('Koneksi ditutup.');
}
main().catch((err) => {
console.error('Terjadi galat:', err.code);
process.exit(1);
});Menjalankan contoh.js dari Terminal #
Eksekusi program dari terminal — di komputer Anda, cukup node contoh.js dari dalam folder chapter; program memakai port 3306 secara default:
-- @test-bash
DB_PORT=3306 node content/mysql/integrasi-aplikasi/mysql-dan-nodejs/contoh.jsOutput yang Dihasilkan:
Daftar produk:
1 | Kopi Toraja | 52000
2 | Teh Melati | 28000
3 | Gula Aren | 32000
Produk di bawah 40000:
2 | Teh Melati
3 | Gula Aren
Koneksi ditutup.Bedah Kode Baris-per-Baris #
const mysql = require('mysql2/promise'): memuat modul varian promise API darimysql2. Modul utamamysql2menyediakan gaya callback; subpath/promisemembungkus semuanya menjadiPromiseyang bisa di-await. Bila folder proyek Anda memakai ES Module (import), padanannya adalahimport mysql from 'mysql2/promise'.async function main(): seluruh tubuh program dibungkus fungsi asinkron karenaawaithanya boleh dipakai di dalamnya — polamain().catch(...)adalah idiom standar Node.js untuk menangkap error di titik teratas.await mysql.createConnection({...}): membuka koneksi tunggal. Berbeda dari Python yang sinkron, di sinicreateConnectionmengembalikanPromise— kataawaitmembuat kita menunggu handshake TCP dan autentikasi selesai sebelum lanjut.Number(...)memastikan port berupa angka, bukan string dari lingkungan.const [rows] = await koneksi.query('SELECT ...'): destructuring array. Hasilqueryadalah pasangan[rows, fields]— elemen pertama baris data, elemen kedua metadata kolom. Kita hanya memakairows, jadi hanya itu yang diikat namanya.rows.forEach((r) => ...):rowsberupa array objek — setiap baris sudah menjadi objek dengan nama kolom sebagai kunci (r.id,r.nama,r.harga), tidak seperti tuple Python yang harus dibongkar urutan.await koneksi.query('... WHERE harga < ?', [40000]): parameterized query. Placeholder di driver mysql adalah?, nilainya dikirim sebagai array[40000]sesuai urutan placeholder. Sama seperti%sdi PyMySQL, nilai tidak pernah digabung ke teks SQL.await koneksi.end(): menutup koneksi dengan sopan — mengirim sapaan penutup ke server, berbeda daridestroy()yang memutus socket mentah.main().catch((err) => { ... process.exit(1); }): galat di mana pun di dalammain— koneksi ditolak, SQL salah — mengalir ke satu penangan teratas;err.codememuat kode error driver (misalnyaER_ACCESS_DENIED_ERRORatauECONNREFUSED), dan exit code1menandai kegagalan ke sistem operasi.
Promise versus Callback #
mysql2 mewarisi dua gaya API sekaligus. Gaya callback — konvensi lama Node.js dengan argumen (err, hasil) di posisi terakhir — tampak seperti ini:
const mysql = require('mysql2');
const koneksi = mysql.createConnection({
host: '127.0.0.1', port: 3306, user: 'root', password: '', database: 'belajar_app',
});
koneksi.query('SELECT id, nama, harga FROM produk ORDER BY id', (err, rows) => {
if (err) {
console.error('galat:', err.code);
return;
}
rows.forEach((r) => console.log(`${r.id} | ${r.nama}`));
koneksi.end();
});Gaya ini berfungsi, tetapi alurnya menjalar ke dalam: setiap langkah berikutnya harus ditulis di dalam fungsi callback langkah sebelumnya, dan urutan eksekusi program tidak lagi mengikuti urutan penulisan barisnya — fenomena klasik bernama callback hell. Gaya Promise dengan await yang kita pakai di contoh.js menuliskan langkah-langkah berurutan seperti kode sinkron: koneksi dulu, query, cetak, tutup; error ditangkap satu kali di catch. Untuk kode baru, mysql2/promise adalah pilihan default yang masuk akal.
Membersihkan Latihan #
Program hanya membaca, jadi data masih utuh. Kita jatuhkan database latihan lewat terminal:
-- @test-bash
mysql -h 127.0.0.1 -P 3306 -u root -e "DROP DATABASE IF EXISTS belajar_app;"Referensi #
Koneksi tunggal di contoh.js cukup untuk satu skrip sekali jalan — tetapi server web menangani banyak request serentak, dan membuka koneksi baru untuk tiap request membayar mahal. Chapter berikutnya mengukur biayanya secara nyata, lalu memperkenalkan senjata pamungkasnya: Database Connection Pooling.
Berkas Sumber
Berkas pendukung halaman ini dapat diunduh dan dijalankan langsung sesuai penjelasan di atas.
contoh.js
Unduh berkas// contoh.js — akses MySQL dari Node.js dengan mysql2 (promise API).
// Jalankan dari folder chapter: node contoh.js
// Port default 3306; timpa lewat variabel lingkungan DB_PORT
// bila server MySQL Anda berjalan di port lain.
const mysql = require('mysql2/promise');
async function main() {
const koneksi = await mysql.createConnection({
host: '127.0.0.1',
port: Number(process.env.DB_PORT || 3306),
user: 'root',
password: '',
database: 'belajar_app',
});
const [rows] = await koneksi.query(
'SELECT id, nama, harga FROM produk ORDER BY id'
);
console.log('Daftar produk:');
rows.forEach((r) => console.log(` ${r.id} | ${r.nama} | ${r.harga}`));
const [murah] = await koneksi.query(
'SELECT id, nama FROM produk WHERE harga < ? ORDER BY id',
[40000]
);
console.log('Produk di bawah 40000:');
murah.forEach((r) => console.log(` ${r.id} | ${r.nama}`));
await koneksi.end();
console.log('Koneksi ditutup.');
}
main().catch((err) => {
console.error('Terjadi galat:', err.code);
process.exit(1);
});