Chapter Koneksi dan Cursor menutup dengan janji membahas kapan koneksi dibuka dan ditutup dengan benar. Pertanyaan itu penting karena koneksi adalah resource nyata: file yang terkunci, memori yang terpakai, dan — pada database server — slot koneksi yang jumlahnya terbatas. Program yang membuka koneksi berkali-kali tanpa menutup, atau menahan satu koneksi selamanya sambil menggunjingkan database dari pemakai lain, adalah program yang lambat laun tersesat. Bab ini merumuskan kebiasaan pengelolaan koneksi yang bisa dibawa ke database apa pun.

Biaya Sebuah Koneksi #

Biaya membuka koneksi berbeda jauh antara SQLite dan database server:

AspekSQLiteDatabase server (PostgreSQL, MySQL)
Membuka koneksimembuka satu file, sangat murahkoneksi jaringan, autentikasi, sesi — mahal
Jumlah koneksi serentakpraktis tak dibatasidibatasi konfigurasi server, umumnya puluhan
Connection poolingtidak dibutuhkanstandar di aplikasi web

Untuk SQLite, aturannya longgar: buka koneksi per unit kerja — satu sesi CLI, satu eksekusi skrip, satu test — lalu tutup. Untuk database server, membuka koneksi baru untuk setiap request web itu boros; aplikasi memakai connection pool: kumpulan koneksi yang dibuka sekali dan dipinjamkan bergantian.

Kebiasaan try/finally dari Chapter Koneksi dan Cursor bekerja, tetapi Python punya alat yang lebih rapi untuk objek yang punya method close(): contextlib.closing():

python
from contextlib import closing
import sqlite3

with closing(sqlite3.connect(":memory:")) as conn:
    conn.execute("CREATE TABLE t (a)")
    conn.execute("INSERT INTO t VALUES (1)")
    conn.commit()
    print("Baris di dalam blok:", conn.execute("SELECT COUNT(*) FROM t").fetchone()[0])

try:
    conn.execute("SELECT 1")
except sqlite3.ProgrammingError as e:
    print("Galat:", e)

Output yang Dihasilkan:

text
Baris di dalam blok: 1
Galat: Cannot operate on a closed database.

Blok with closing(...) menjamin conn.close() terpanggil bagaimana pun blok berakhir — termasuk saat exception. Percobaan query setelah blok membuktikan koneksi benar-benar tertutup. Ingat beda dua pola with pada SQLite:

| Pola | Yang dikelola | Tidak mengurus | | with conn: | commit / rollback | penutupan | | with closing(conn): | penutupan | commit / rollback |

Untuk mengelola keduanya sekaligus, keduanya disarangkan — with closing(connect(...)) as conn: di luar, with conn: di sekitar rangkaian perubahan.

Health Check Koneksi #

Pada aplikasi berumur panjang — daemon, worker antrean — koneksi bisa terputus diam-diam di tengah jalan. Pemeriksaan kesehatan termurah adalah query paling ringan yang ada: SELECT 1:

python
import sqlite3

def cek_kesehatan(conn):
    try:
        return conn.execute("SELECT 1").fetchone() == (1,)
    except sqlite3.Error:
        return False

conn = sqlite3.connect(":memory:")
print("Sebelum close :", cek_kesehatan(conn))
conn.close()
print("Setelah close :", cek_kesehatan(conn))

Output yang Dihasilkan:

text
Sebelum close : True
Setelah close : False

Fungsi cek_kesehatan() menelan seluruh galat turunan sqlite3.Error dan melaporkan keadaan sebagai boolean — pola yang lazim pada pemantauan aplikasi berjalan (health check endpoint), karena pemanggil hanya butuh tahu “sehat atau tidak”, bukan bentuk galatnya. Pada database server, query SELECT 1 berperan sama: ringan di server dan cukup untuk membuktikan sesi masih hidup.

Timeout dan Batas Koneksi #

Ketika dua prosess menulis ke database SQLite yang sama, penulis kedua menunggu sampai penulis pertama selesai. Parameter timeout pada connect() mengatur berapa lama menunggu sebelum menyerah dengan galat “database is locked”:

python
import sqlite3

conn_default = sqlite3.connect(":memory:")
conn_cepat = sqlite3.connect(":memory:", timeout=2.5)
print("default        :", conn_default.execute("PRAGMA busy_timeout").fetchone()[0], "ms")
print("timeout=2.5   :", conn_cepat.execute("PRAGMA busy_timeout").fetchone()[0], "ms")
conn_default.close()
conn_cepat.close()

Output yang Dihasilkan:

text
default        : 5000 ms
timeout=2.5   : 2500 ms

Nilai timeout dalam detik disimpan SQLite sebagai busy timeout dalam milidetik — bawaan 5 detik. Naikkan nilai ini di aplikasi dengan banyak penulis serentak; turunkan bila lebih baik gagal cepat daripada menggantung request.

Dengan koneksi yang terkelola, tahap terakhir section ini memandang ke depan: kapan SQLite saja tidak cukup dan bagaimana wujud kode kita di PostgreSQL dan MySQL — materi Chapter Pengenalan PostgreSQL dan MySQL.