Cara Koneksi Python ke MySQL: mysql-connector, PyMySQL, dan SQLAlchemy Lengkap 2026

setelah kemarin main dengan SQLite yang cukup satu file data.db, langkah selanjutnya adalah MySQL, database yang paling sering saya temui di dunia kerja. jika SQLite cocok buat prototype, maka MySQL adalah tempat data kalian tinggal kalau sudah butuh banyak user, banyak koneksi, dan akses barengan.
saya masih ingat pertama kali koneksi Python ke MySQL malah error Authentication plugin 'caching_sha2_password' is not supported, padahal password sudah benar. ternyata MySQL 8 ganti auth default dan driver saya masih versi lama. sejak kejadian itu, saya selalu mulai tutorial koneksi dari persiapan driver yang benar, bukan langsung ke connect() 🙂.
jika kalian baru dari belajar SQLite di Python, pola koneksinya mirip, cuma sekarang butuh server MySQL yang jalan. dan kalau belum paham venv, baca dulu pip dan virtual environment biar install drivernya tidak berantakan.
Daftar Isi
- 1. Persiapan: MySQL dan virtual environment
- 2. mysql-connector vs PyMySQL vs SQLAlchemy
- 3. Koneksi pertama dengan mysql-connector-python
- 4. CRUD lengkap dan parameterized query
- 5. PyMySQL untuk hosting dan Django
- 6. SQLAlchemy 2.0 ORM yang modern
- 7. Connection pooling dan error handling
- 8. Studi kasus: simpan hasil scraping ke MySQL
- 9. Troubleshooting 2026
1. Persiapan: MySQL dan Virtual Environment
jika sudah selesai install MySQL, maka akan ada service MySQL yang jalan di port 3306, cek dulu sebelum coding:
# cek service MySQL jalan
mysql -u root -p -e "SELECT VERSION();"
# atau kalau pakai Docker (paling enak di 2026)
docker run --name mysql-dev -e MYSQL_ROOT_PASSWORD=root -e MYSQL_DATABASE=belajar -p 3306:3306 -d mysql:8.4
maka akan muncul versi, di 2026 idealnya 8.4.x LTS. jika masih 5.7, segera upgrade, soalnya 5.7 sudah tidak dapat patch.
selanjutnya bikin project dengan venv, jangan install driver di Python global:
mkdir koneksi-mysql && cd koneksi-mysql
python -m venv .venv
# Windows CMD
.venv\Scripts\activate
# Windows PowerShell
.venv\Scripts\Activate.ps1
# Mac/Linux
source .venv/bin/activate
python -m pip install --upgrade pip
pip install mysql-connector-python pymysql sqlalchemy python-dotenv
buat file .env untuk simpan kredensial, jangan hardcode password di kode:
# .env
DB_HOST=localhost
DB_PORT=3306
DB_USER=root
DB_PASSWORD=root
DB_NAME=belajar
dan masukkan ke .gitignore:
.venv/
.env
__pycache__/
*.pyc
2. mysql-connector vs PyMySQL vs SQLAlchemy
jika kalian bingung milih driver, maka tabel ini yang biasanya saya tunjukkin dulu:
| Driver | Pembuat | Kelebihan | Kekurangan | Cocok untuk |
|---|---|---|---|---|
| mysql-connector-python | Resmi Oracle | support MySQL 8.4, caching_sha2_password langsung jalan, punya pooling bawaan | agak lebih berat, rilis agak lambat | pemula, project baru 2026, butuh fitur resmi |
| PyMySQL | Komunitas | pure python, ringan, dipakai Django, install cepat | tidak ada pooling bawaan, auth baru butuh versi 1.1+ | hosting shared, project Django lama |
| mysqlclient | Komunitas | paling cepat (C extension) | butuh compiler di Windows, ribet install | production Linux yang butuh performa maksimal |
| SQLAlchemy 2.0 | ORM | bukan driver, tapi bungkus driver di atas, punya ORM + pooling + async | learning curve agak curam | aplikasi menengah-besar, butuh model |
catatan 2026: SQLAlchemy butuh driver di bawahnya, biasanya pymysql atau mysql-connector. jadi kalian tetap install salah satu driver di atas, lalu SQLAlchemy tinggal pakai mysql+pymysql://... atau mysql+mysqlconnector://....
untuk tutorial ini, saya sarankan mulai dari mysql-connector-python dulu, kalau sudah lancar baru naik ke SQLAlchemy.
3. Koneksi Pertama dengan mysql-connector-python
jika driver sudah terinstall, maka koneksi pertamanya sesederhana ini:
import os
import mysql.connector
from dotenv import load_dotenv
load_dotenv() # baca .env
conn = mysql.connector.connect(
host=os.getenv("DB_HOST", "localhost"),
port=int(os.getenv("DB_PORT", "3306")),
user=os.getenv("DB_USER", "root"),
password=os.getenv("DB_PASSWORD", ""),
database=os.getenv("DB_NAME", "belajar"),
)
print("koneksi berhasil, server:", conn.get_server_info())
# cek apakah koneksi masih hidup
print("connected?", conn.is_connected())
conn.close()
pakai with biar koneksi otomatis ketutup, mirip with open() di file handling:
from contextlib import closing
with closing(mysql.connector.connect(
host="localhost", user="root", password="root", database="belajar"
)) as conn:
with conn.cursor(dictionary=True) as cur:
cur.execute("SELECT VERSION() as v")
print(cur.fetchone())
# keluar with, koneksi dan cursor otomatis close, bahkan kalau error
tip dari saya: selalu pakai
dictionary=Truekalau mau hasilfetchjadidict, lebih enak dibaca daripada tuple. kalau butuh performa mentah untuk jutaan baris, baru pakai cursor biasa.
4. CRUD Lengkap dan Parameterized Query
jika koneksi sudah oke, maka langkah selanjutnya adalah bikin tabel dan mainkan CRUD, polanya sama seperti di SQLite, cuma placeholder-nya beda:
import mysql.connector
from dotenv import load_dotenv
import os
load_dotenv()
def get_conn():
return mysql.connector.connect(
host=os.getenv("DB_HOST"), user=os.getenv("DB_USER"),
password=os.getenv("DB_PASSWORD"), database=os.getenv("DB_NAME")
)
# 1. buat tabel
with get_conn() as conn:
with conn.cursor() as cur:
cur.execute("""
CREATE TABLE IF NOT EXISTS produk (
id INT AUTO_INCREMENT PRIMARY KEY,
nama VARCHAR(100) NOT NULL,
harga INT NOT NULL,
stok INT DEFAULT 0,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
) ENGINE=InnoDB
""")
conn.commit()
print("tabel siap")
Create, Read, Update, Delete
# CREATE - jangan pakai f-string, pakai %s
def tambah_produk(nama, harga, stok):
with get_conn() as conn:
with conn.cursor() as cur:
cur.execute(
"INSERT INTO produk (nama, harga, stok) VALUES (%s, %s, %s)",
(nama, harga, stok)
)
conn.commit()
return cur.lastrowid
# CREATE banyak sekaligus, jauh lebih cepat
def tambah_banyak(data_list):
# data_list = [("Mouse", 150000, 10), ("Keyboard", 300000, 5)]
with get_conn() as conn:
with conn.cursor() as cur:
cur.executemany(
"INSERT INTO produk (nama, harga, stok) VALUES (%s, %s, %s)",
data_list
)
conn.commit()
print(f"{cur.rowcount} baris masuk")
# READ
def ambil_semua():
with get_conn() as conn:
with conn.cursor(dictionary=True) as cur:
cur.execute("SELECT * FROM produk ORDER BY id DESC")
return cur.fetchall()
def cari_produk(keyword):
with get_conn() as conn:
with conn.cursor(dictionary=True) as cur:
# LIKE dengan parameter, jangan concat string
cur.execute("SELECT * FROM produk WHERE nama LIKE %s", (f"%{keyword}%",))
return cur.fetchall()
# UPDATE
def update_harga(id_produk, harga_baru):
with get_conn() as conn:
with conn.cursor() as cur:
cur.execute("UPDATE produk SET harga=%s WHERE id=%s", (harga_baru, id_produk))
conn.commit()
return cur.rowcount # berapa baris keupdate
# DELETE
def hapus_produk(id_produk):
with get_conn() as conn:
with conn.cursor() as cur:
cur.execute("DELETE FROM produk WHERE id=%s", (id_produk,))
conn.commit()
return cur.rowcount
jika kalian perhatikan, maka placeholder di MySQL pakai %s untuk semua tipe, tidak peduli string atau int. ini beda dengan SQLite yang pakai ?. dan jangan pernah tulis seperti ini:
# ❌ JANGAN - rentan SQL Injection
cur.execute(f"SELECT * FROM produk WHERE nama = '{user_input}'")
# ✅ PAKAI INI - aman, driver yang escape
cur.execute("SELECT * FROM produk WHERE nama = %s", (user_input,))
Transaksi: commit dan rollback
try:
conn = get_conn()
conn.start_transaction()
cur = conn.cursor()
cur.execute("UPDATE produk SET stok = stok - 1 WHERE id = %s", (1,))
cur.execute("INSERT INTO penjualan (produk_id, jumlah) VALUES (%s, %s)", (1, 1))
conn.commit()
print("transaksi sukses")
except mysql.connector.Error as e:
conn.rollback()
print("transaksi gagal, di-rollback:", e)
finally:
cur.close()
conn.close()
tanpa commit, data tidak akan kesimpan. tanpa rollback saat error, data bisa setengah jadi.
5. PyMySQL untuk Hosting dan Django
jika kalian deploy ke hosting yang tidak kasih akses install mysql-connector, maka PyMySQL sering jadi penyelamat karena pure python dan ringan:
import pymysql
from dotenv import load_dotenv
import os
load_dotenv()
conn = pymysql.connect(
host=os.getenv("DB_HOST"),
user=os.getenv("DB_USER"),
password=os.getenv("DB_PASSWORD"),
database=os.getenv("DB_NAME"),
charset="utf8mb4",
cursorclass=pymysql.cursors.DictCursor, # biar hasil dict
autocommit=False
)
with conn:
with conn.cursor() as cur:
cur.execute("SELECT * FROM produk LIMIT 5")
for row in cur.fetchall():
print(row)
conn.commit()
beda tipis dengan mysql-connector, cuma import dan parameter charset yang perlu diisi utf8mb4 biar emoji dan karakter Indonesia aman. untuk Django 2026, PyMySQL masih sering dipakai dengan trik pymysql.install_as_MySQLdb() di manage.py.
6. SQLAlchemy 2.0 ORM yang Modern
jika project sudah agak besar dan kalian bosan nulis SQL manual, maka SQLAlchemy 2.0 adalah langkah selanjutnya. sejak versi 2.0 (2023), syntax-nya jauh lebih rapi dan support async:
pip install sqlalchemy pymysql
from sqlalchemy import create_engine, String, Integer
from sqlalchemy.orm import DeclarativeBase, Mapped, mapped_column, Session
import os
from dotenv import load_dotenv
load_dotenv()
# URL format: mysql+pymysql://user:password@host:port/dbname
url = f"mysql+pymysql://{os.getenv('DB_USER')}:{os.getenv('DB_PASSWORD')}@{os.getenv('DB_HOST')}/{os.getenv('DB_NAME')}"
engine = create_engine(url, echo=True, pool_pre_ping=True)
class Base(DeclarativeBase):
pass
class Produk(Base):
__tablename__ = "produk_orm"
id: Mapped[int] = mapped_column(primary_key=True, autoincrement=True)
nama: Mapped[str] = mapped_column(String(100))
harga: Mapped[int] = mapped_column(Integer)
stok: Mapped[int] = mapped_column(Integer, default=0)
# buat tabel
Base.metadata.create_all(engine)
# CREATE
with Session(engine) as session:
mouse = Produk(nama="Mouse Wireless", harga=150000, stok=10)
session.add(mouse)
session.commit()
print("id baru:", mouse.id)
# tambah banyak
with Session(engine) as session:
session.add_all([
Produk(nama="Keyboard", harga=300000, stok=5),
Produk(nama="Webcam", harga=500000, stok=3),
])
session.commit()
# READ
with Session(engine) as session:
produk = session.get(Produk, 1)
print(produk.nama, produk.harga)
# query dengan filter
from sqlalchemy import select
stmt = select(Produk).where(Produk.harga > 200000).order_by(Produk.harga)
for p in session.scalars(stmt):
print(p.nama, p.harga)
# UPDATE
with Session(engine) as session:
p = session.get(Produk, 1)
p.harga = 175000
session.commit()
# DELETE
with Session(engine) as session:
p = session.get(Produk, 1)
session.delete(p)
session.commit()
enaknya ORM, kalian tidak perlu hafal INSERT atau UPDATE, cukup main object. tapi ingat, ORM tetap generate SQL di belakang, jadi untuk query kompleks, cek log echo=True biar tahu SQL apa yang jalan.
untuk project FastAPI modern 2026, banyak yang sudah pakai
asyncmyatauaiomysqlbiar bisaasync defdanawait session.execute(). polanya sama, cuma engine-nyacreate_async_engine("mysql+asyncmy://..."). kalau aplikasi kalian masih sync, yang di atas sudah cukup.
7. Connection Pooling dan Error Handling
jika aplikasi kalian buka tutup koneksi tiap request, maka MySQL bakal kewalahan. solusinya pooling:
mysql-connector pooling bawaan:
from mysql.connector import pooling
dbconfig = {
"host": "localhost", "user": "root", "password": "root",
"database": "belajar"
}
pool = pooling.MySQLConnectionPool(pool_name="mypool", pool_size=5, **dbconfig)
# pakai
conn = pool.get_connection()
try:
with conn.cursor(dictionary=True) as cur:
cur.execute("SELECT * FROM produk")
print(cur.fetchall())
finally:
conn.close() # dikembalikan ke pool, bukan benar-benar close
SQLAlchemy pooling (lebih canggih):
engine = create_engine(url, pool_size=10, max_overflow=20, pool_pre_ping=True, pool_recycle=3600)
# pool_pre_ping=True cek koneksi masih hidup sebelum dipakai, penting untuk MySQL yang suka timeout
untuk error handling, jangan tangkap Exception polos, tangkap yang spesifik seperti di error handling Python:
import mysql.connector
from mysql.connector import errorcode
try:
conn = mysql.connector.connect(host="localhost", user="root", password="salah", database="belajar")
except mysql.connector.Error as err:
if err.errno == errorcode.ER_ACCESS_DENIED_ERROR:
print("username atau password salah, cek .env")
elif err.errno == errorcode.ER_BAD_DB_ERROR:
print("database tidak ada, bikin dulu CREATE DATABASE belajar")
elif err.errno == errorcode.CR_CONN_HOST_ERROR:
print("MySQL tidak jalan atau port 3306 ketutup, cek docker atau service")
else:
print(f"error lain: {err}")
else:
conn.close()
dan untuk retry sederhana saat scraping:
import time
def query_dengan_retry(query, params, max_retry=3):
for i in range(max_retry):
try:
with get_conn() as conn:
with conn.cursor() as cur:
cur.execute(query, params)
conn.commit()
return cur.rowcount
except mysql.connector.errors.OperationalError as e:
print(f"retry {i+1}/{max_retry} karena {e}")
time.sleep(1)
raise RuntimeError("gagal setelah 3x coba")
8. Studi Kasus: Simpan Hasil Scraping ke MySQL
jika sudah paham CRUD, maka studi kasus paling nyata adalah simpan hasil scraping, ini yang sering saya pakai buat kumpulin harga produk:
import requests
from bs4 import BeautifulSoup
import mysql.connector
from dotenv import load_dotenv
import os
load_dotenv()
def get_conn():
return mysql.connector.connect(
host=os.getenv("DB_HOST"), user=os.getenv("DB_USER"),
password=os.getenv("DB_PASSWORD"), database=os.getenv("DB_NAME")
)
# 1. siapin tabel
with get_conn() as conn:
with conn.cursor() as cur:
cur.execute("""
CREATE TABLE IF NOT EXISTS hasil_scraping (
id INT AUTO_INCREMENT PRIMARY KEY,
judul VARCHAR(255) NOT NULL,
harga INT,
url VARCHAR(500),
scraped_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
UNIQUE KEY uniq_judul (judul)
) ENGINE=InnoDB
""")
conn.commit()
# 2. fungsi scraping ala kadarnya
def scrape_contoh():
# contoh ambil judul dari httpbin, ganti dengan target kalian
resp = requests.get("https://httpbin.org/html", timeout=10)
soup = BeautifulSoup(resp.text, "html.parser")
judul = soup.find("h1").get_text(strip=True) if soup.find("h1") else "Tanpa Judul"
# simulasi harga
return [(judul, 150000, "https://httpbin.org/html")]
# 3. simpan dengan executemany + ON DUPLICATE KEY UPDATE biar tidak duplikat
data = scrape_contoh()
print(f"hasil scraping: {data}")
with get_conn() as conn:
with conn.cursor() as cur:
cur.executemany("""
INSERT INTO hasil_scraping (judul, harga, url)
VALUES (%s, %s, %s)
ON DUPLICATE KEY UPDATE harga=VALUES(harga), scraped_at=NOW()
""", data)
conn.commit()
print(f"{cur.rowcount} baris tersimpan/diupdate")
# 4. cek hasil
with get_conn() as conn:
with conn.cursor(dictionary=True) as cur:
cur.execute("SELECT * FROM hasil_scraping ORDER BY scraped_at DESC LIMIT 5")
for row in cur.fetchall():
print(row)
jika data scraping ribuan, maka jangan execute satu-satu di loop, pakai executemany seperti di atas, kecepatannya bisa 10x lipat. dan ON DUPLICATE KEY UPDATE bikin data tidak dobel kalau judul sama, tinggal update harga dan waktunya.
untuk scraping beneran dengan BeautifulSoup lengkap, kalian bisa lanjut baca belajar web scraping BeautifulSoup lalu sambungkan ke pola simpan MySQL ini.
9. Troubleshooting 2026 yang Paling Sering Muncul
jika koneksi gagal, maka cek urutan ini, 90% masalah selesai di sini:
| Error | Penyebab | Solusi |
|---|---|---|
1045 Access denied | user/password salah atau host tidak diizinkan | cek .env, atau CREATE USER 'user'@'%' IDENTIFIED BY 'pass' |
2003 Can't connect | MySQL tidak jalan atau port ketutup | docker ps, atau `netstat -an |
1049 Unknown database | database belum dibuat | CREATE DATABASE belajar CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci |
caching_sha2_password | driver lama | pip install --upgrade mysql-connector-python atau ganti ALTER USER 'root'@'localhost' IDENTIFIED WITH mysql_native_password BY 'root' |
SSL connection error | MySQL 8.4 paksa SSL | tambah ssl_disabled=True di connect() untuk lokal, atau setup sertifikat untuk production |
MySQL server has gone away | koneksi idle terlalu lama | pakai pool_pre_ping=True di SQLAlchemy atau pool_recycle |
jangan khawatir kalau error SSL muncul di lokal, itu wajar di MySQL 8.4. untuk development,
ssl_disabled=Truetidak apa-apa. untuk production, jangan dimatikan, setup SSL yang benar atau pakaissl_cadanssl_verify_cert.
10. Tips Aman dan Cepat di 2026
- pakai
.env+python-dotenv, jangan pernah commit password ke git. di server, set environment variable langsung. - selalu pakai
utf8mb4, bukanutf8biasa.utf8di MySQL cuma 3-byte, emoji 4-byte akan error.utf8mb4yang benar. - pakai
withdancommityang jelas, jangan andalkanautocommit=Truekecuali untuk script sekali jalan. - untuk insert massal,
executemany+ transaksi, jangan loopexecute+committiap baris, lambat dan bikin log penuh. - di 2026, pertimbangkan
uvpengganti pip kalau project besar:uv pip install mysql-connector-pythonjauh lebih cepat, tapi konsep venv tetap sama. - kalau butuh async untuk FastAPI, pakai
asyncmy+ SQLAlchemy async, jangan pakai driver sync diasync def, nanti blocking.
11. Update September 2026: Apa yang Baru dan Perlu Kalian Tahu
jika kalian ikuti update ekosistem Python dan MySQL di 2026, maka ini rangkuman yang paling sering saya ditanya di kelas:
Python 3.13 sudah jadi default di installer baru. kalau kalian install Python hari ini, maka yang kepasang adalah 3.13. mysql-connector-python 9.1+ dan PyMySQL 1.1.1 sudah support 3.13, tapi kalau masih pakai Python 3.11, tetap aman. jangan buru-buru pakai free-threaded build (PEP 703) untuk project database, driver DB-API belum siap untuk tanpa GIL.
MySQL 8.4 LTS vs 9.x. 8.4 LTS itu yang saya pakai di semua tutorial ini dan didukung sampai 2032. MySQL 9.0 dan 9.1 innovation sudah rilis, tapi untuk production saya tetap sarankan 8.4 LTS karena 8.0 sudah EOL April 2026. kalau hosting kalian masih tawarkan 8.0, minta upgrade ke 8.4.
mysql-connector-python 9.1 ada perubahan auth. sekarang caching_sha2_password jadi satu-satunya default, mysql_native_password sudah deprecated dan akan dihapus. jadi kalau masih pakai ALTER USER ... IDENTIFIED WITH mysql_native_password, itu hanya untuk sementara. update driver ke 9.1+ lebih baik daripada ubah auth.
SQLAlchemy + SQLModel makin populer. kalau kalian pakai FastAPI, maka SQLModel (dibuat creator FastAPI) jadi wrapper di atas SQLAlchemy 2.0 + Pydantic v2, jadi model DB dan schema API jadi satu. polanya mirip contoh di ## 6, cuma class Produk(SQLModel, table=True) biar validasi otomatis.
pydantic-settings ganti python-dotenv di project baru. di 2026 banyak template baru pakai:
from pydantic_settings import BaseSettings
class Settings(BaseSettings):
db_host: str = "localhost"
db_user: str = "root"
db_password: str = ""
db_name: str = "belajar"
class Config:
env_file = ".env"
settings = Settings()
# pakai settings.db_host di connect()
lebih rapi daripada os.getenv satu-satu, tapi python-dotenv tetap jalan untuk script kecil.
docker compose jadi cara standar jalankan MySQL lokal. dibanding docker run satu baris, sekarang compose.yaml lebih enak plus healthcheck:
services:
db:
image: mysql:8.4
environment:
MYSQL_ROOT_PASSWORD: root
MYSQL_DATABASE: belajar
ports: ["3306:3306"]
healthcheck:
test: ["CMD", "mysqladmin", "ping", "-h", "localhost"]
interval: 5s
retries: 10
lalu docker compose up -d, dan Python tinggal host=localhost.
uv makin jadi default di tutorial 2026. kalau kalian lihat tutorial baru pakai uv venv dan uv pip install -r requirements.txt, itu sama persis dengan python -m venv dan pip install, cuma 10 sampai 100 kali lebih cepat dan bikin uv.lock otomatis. untuk project yang sudah jalan, tidak wajib migrasi, tapi untuk project baru saya sudah pakai uv.
ringkasnya, kalau project kalian sudah jalan dengan
mysql-connector-python8.4 dan Python 3.12, tidak perlu refactor besar. cukup update driver ke9.1+dan pastikanutf8mb4serta SSL sudah benar, itu sudah cover 90 persen case 2026.
Kesimpulan
- mysql-connector-python itu pilihan default 2026 untuk pemula karena resmi dan support MySQL 8.4, PyMySQL untuk solusi ringan, dan SQLAlchemy 2.0 kalau butuh ORM dan pooling
- koneksi pakai
mysql.connector.connect()denganhost, user, password, database, idealnya baca dari.env - placeholder MySQL pakai
%sdan kirim tuple, jangan pakai f-string biar aman dari SQL Injection - untuk baca tulis massal, pakai
executemanydanON DUPLICATE KEY UPDATEbiar cepat dan tidak duplikat - jangan lupa
commit()setelah tulis danclose()atau pakaiwithbiar koneksi balik ke pool - simpan password di
.env, pakaiutf8mb4, dan aktifkanpool_pre_pingkalau aplikasi jalan lama
habis ini kalian bisa lanjut ke belajar database SQLite buat bandingkan, atau ke pip dan virtual environment kalau venv masih bingung, dan error handling try except buat bikin koneksi yang tahan error.
Baca Juga Mengenai :
Pertanyaan yang Sering Diajukan
Library apa yang terbaik untuk koneksi Python ke MySQL di 2026?
untuk pemula pakai mysql-connector-python karena resmi dari Oracle dan dukung MySQL 8.4. untuk project yang butuh kompatibilitas hosting lama pakai PyMySQL. untuk aplikasi besar pakai SQLAlchemy 2.0 biar bisa ORM dan connection pooling otomatis.
Apa beda mysql-connector-python dan PyMySQL?
mysql-connector-python itu driver resmi Oracle, pure python dan support fitur baru seperti caching_sha2_password. PyMySQL itu driver komunitas, lebih ringan dan sering dipakai di Django, tapi fiturnya agak tertinggal. keduanya pakai DB-API 2.0 jadi kodenya mirip.
Kenapa koneksi MySQL sering error caching_sha2_password?
sejak MySQL 8.0 default auth jadi caching_sha2_password. kalau driver lama belum support, koneksi ditolak. solusinya update ke mysql-connector-python 8.4+ atau PyMySQL 1.1+, atau ganti user ke mysql_native_password sementara.
Bagaimana cara mencegah SQL Injection di Python?
jangan pernah gabung string pakai f-string untuk query. pakai parameterized query dengan placeholder %s lalu kirim tuple parameter ke cursor.execute. driver akan escape otomatis.
Apa itu connection pooling dan kapan perlu?
connection pooling itu kumpulan koneksi yang dipakai ulang tanpa buka tutup terus. perlu kalau aplikasi banyak request seperti API atau scraping ribuan data. SQLAlchemy dan mysql-connector punya pooling bawaan.
Apakah SQLAlchemy wajib untuk koneksi MySQL?
tidak wajib. kalau cuma butuh query sederhana, mysql-connector atau PyMySQL cukup. SQLAlchemy baru terasa manfaatnya kalau butuh ORM, migrasi, dan pooling di project menengah besar.
Bagaimana simpan password MySQL dengan aman di Python?
jangan hardcode di kode. simpan di file .env lalu baca pakai python-dotenv, dan masukkan .env ke .gitignore. di production pakai environment variable atau secret manager.

