Python 3’te sqlite3 Modülünü Kullanma Rehberi
SQLite, sunucusuz, kendi kendine yeten, sıfır yapılandırmalı, işlemsel bir SQL veritabanı motorudur. Hafifliği, kolay entegrasyonu ve kurulum gerektirmemesi sayesinde özellikle masaüstü uygulamaları, mobil uygulamalar, web siteleri (düşük trafikli) ve geliştirme/test süreçleri için ideal bir çözümdür. Python’ın standart kütüphanesinde yer alan sqlite3 modülü, Python uygulamalarınızla SQLite veritabanları arasında sorunsuz bir köprü görevi görür. Bu rehberde, sqlite3 modülünün temel ve ileri düzey kullanımlarını, pratik örneklerle birlikte detaylı bir şekilde inceleyeceğiz.
SQLite3 Neden Kullanılmalı?
Python projelerinizde sqlite3 kullanmayı düşünmeniz için birkaç iyi neden vardır:
- Kolay Kurulum: Harici bir sunucuya veya karmaşık bir yapılandırmaya ihtiyaç duymaz. Sadece bir dosya olarak veritabanınızı oluşturabilirsiniz.
- Hafif ve Hızlı: Küçük ve orta ölçekli projeler için oldukça hızlı ve kaynak dostudur.
- Gömülü Yapı: Uygulamanızın bir parçası olarak dağıtılabilir, bu da dağıtım ve yönetim maliyetlerini azaltır.
- Standart Kütüphane: Ekstra bir paket (pip install) kurmaya gerek yoktur, Python ile birlikte gelir.
- SQL Desteği: Standart SQL sorgu dilini kullanarak veri manipülasyonu yapmanızı sağlar.
Veritabanına Bağlanma ve Tablo Oluşturma
Bir SQLite veritabanı ile çalışmaya başlamak için öncelikle ona bağlanmanız ve ardından üzerinde işlemler yapacağınız tabloları oluşturmanız gerekir.
Veritabanına Bağlanma
sqlite3.connect() fonksiyonu ile bir veritabanı dosyasına bağlanırsınız. Eğer belirtilen isimde bir dosya yoksa, otomatik olarak oluşturulur.
import sqlite3
veritabani.db adında bir dosyaya bağlan
Eğer dosya yoksa, bu isimde yeni bir veritabanı dosyası oluşturulur.
":memory:" kullanarak bellek içi (geçici) bir veritabanı da oluşturabilirsiniz.
try:
conn = sqlite3.connect('ornek_veritabani.db')
print("Veritabanına başarıyla bağlanıldı.")
except sqlite3.Error as e:
print(f"Veritabanına bağlanırken hata oluştu: {e}")
Veritabanı üzerinde işlem yapmak için bir imleç (cursor) nesnesi oluşturulur.
İmleç, SQL komutlarını yürütmek ve sonuçları almak için kullanılır.
cursor = conn.cursor()
Tablo Oluşturma
Bağlantı kurulduktan sonra, SQL CREATE TABLE komutunu kullanarak tablolarınızı oluşturabilirsiniz. cursor.execute() metodu, SQL sorgularını çalıştırmak için kullanılır.
'kullanicilar' adında bir tablo oluşturalım.
id: Otomatik artan birincil anahtar
ad: Metin türünde, boş olamaz
email: Metin türünde, benzersiz ve boş olamaz
yas: Tam sayı türünde
try:
cursor.execute('''
CREATE TABLE IF NOT EXISTS kullanicilar (
id INTEGER PRIMARY KEY AUTOINCREMENT,
ad TEXT NOT NULL,
email TEXT NOT NULL UNIQUE,
yas INTEGER
)
''')
# Değişiklikleri veritabanına kaydet (commit et)
conn.commit()
print("Kullanicilar tablosu başarıyla oluşturuldu veya zaten mevcut.")
except sqlite3.Error as e:
print(f"Tablo oluşturulurken hata oluştu: {e}")
İşlem bittikten sonra bağlantıyı kapatmak önemlidir.
Ancak, şimdilik açık bırakıyoruz ki sonraki işlemleri yapabilelim.
conn.close()
conn.commit() çağrısı, yapılan değişiklikleri kalıcı olarak veritabanına kaydeder. CREATE TABLE gibi DDL (Veri Tanımlama Dili) işlemleri için de commit önemlidir.
CRUD Operasyonları: Veri Ekleme, Okuma, Güncelleme, Silme
Veritabanı işlemlerinin temelini oluşturan CRUD (Create, Read, Update, Delete) operasyonları, sqlite3 modülü ile kolayca gerçekleştirilebilir.
Veri Ekleme (INSERT)
INSERT INTO komutu ile tabloya yeni kayıtlar ekleyebilirsiniz. SQL enjeksiyon saldırılarını önlemek ve veri tipleriyle ilgili sorunları gidermek için parametreli sorgular kullanmak en iyi uygulamadır.
Tek bir kullanıcı ekleme
try:
cursor.execute("INSERT INTO kullanicilar (ad, email, yas) VALUES (?, ?, ?)",
("Ali Can", "ali.can@example.com", 25))
conn.commit()
print("Ali Can başarıyla eklendi.")
except sqlite3.Error as e:
print(f"Veri eklenirken hata oluştu: {e}")
Birden fazla kullanıcı ekleme (executemany)
kullanicilar_listesi = [
("Ayşe Yılmaz", "ayse.yilmaz@example.com", 30),
("Mehmet Demir", "mehmet.demir@example.com", 22),
("Fatma Kaya", "fatma.kaya@example.com", 28)
]
try:
cursor.executemany("INSERT INTO kullanicilar (ad, email, yas) VALUES (?, ?, ?)",
kullanicilar_listesi)
conn.commit()
print("Birden fazla kullanıcı başarıyla eklendi.")
except sqlite3.Error as e:
print(f"Toplu veri eklenirken hata oluştu: {e}")
Veri Okuma (SELECT)
SELECT komutu ile tablodaki verileri sorgulayabilirsiniz. cursor nesnesi, sorgu sonuçlarını almak için çeşitli metodlar sunar:
fetchone(): Sorgunun bir sonraki satırını döndürür veya başka satır yoksaNonedöndürür.fetchall(): Sorgunun tüm kalan satırlarını bir liste olarak döndürür.fetchmany(size): Sorgunun sonrakisizekadar satırını döndürür.- Doğrudan
cursorüzerinde döngü yapmak: Her satırı tek tek işlemek için kullanılabilir.
Tüm kullanıcıları seçme
print("\n--- Tüm Kullanıcılar ---")
cursor.execute("SELECT id, ad, email, yas FROM kullanicilar")
for row in cursor.fetchall():
print(f"ID: {row[0]}, Ad: {row[1]}, Email: {row[2]}, Yaş: {row[3]}")
Belirli bir koşula göre kullanıcı seçme
print("\n--- Yaşı 25'ten Büyük Kullanıcılar ---")
cursor.execute("SELECT ad, email FROM kullanicilar WHERE yas > ?", (25,))
for row in cursor.fetchall():
print(f"Ad: {row[0]}, Email: {row[1]}")
Tek bir sonuç döndürme (fetchone)
print("\n--- İlk Kullanıcı ---")
cursor.execute("SELECT ad FROM kullanicilar ORDER BY id LIMIT 1")
ilk_kullanici = cursor.fetchone()
if ilk_kullanici:
print(f"İlk kullanıcı adı: {ilk_kullanici[0]}")
Varsayılan olarak, fetchone() ve fetchall() metodları, satırları tuple olarak döndürür. Sütunlara isimleriyle erişmek isterseniz, conn.row_factory = sqlite3.Row ayarını yapabilirsiniz. Bunu “İleri Seviye Konular” bölümünde ele alacağız.
Veri Güncelleme (UPDATE)
UPDATE komutu ile mevcut bir kaydın verilerini değiştirebilirsiniz. WHERE koşulu, hangi kayıtların güncelleneceğini belirler.
Bir kullanıcının yaşını güncelleme
try:
cursor.execute("UPDATE kullanicilar SET yas = ? WHERE ad = ?", (26, "Ali Can"))
conn.commit()
print("\nAli Can'ın yaşı başarıyla güncellendi.")
except sqlite3.Error as e:
print(f"Veri güncellenirken hata oluştu: {e}")
Güncellenmiş veriyi kontrol edelim
print("\n--- Güncellenmiş Ali Can ---")
cursor.execute("SELECT ad, yas FROM kullanicilar WHERE ad = 'Ali Can'")
updated_ali = cursor.fetchone()
if updated_ali:
print(f"Ad: {updated_ali[0]}, Yeni Yaş: {updated_ali[1]}")
Veri Silme (DELETE)
DELETE FROM komutu ile tablodan kayıtları silebilirsiniz. WHERE koşulu, hangi kayıtların silineceğini belirler. Koşul belirtmezseniz, tablodaki tüm kayıtlar silinir!
Bir kullanıcıyı silme
try:
cursor.execute("DELETE FROM kullanicilar WHERE ad = ?", ("Mehmet Demir",))
conn.commit()
print("\nMehmet Demir başarıyla silindi.")
except sqlite3.Error as e:
print(f"Veri silinirken hata oluştu: {e}")
Silme sonrası kalan kullanıcıları kontrol edelim
print("\n--- Silme Sonrası Kalan Kullanıcılar ---")
cursor.execute("SELECT ad FROM kullanicilar")
for row in cursor.fetchall():
print(f"Kalan Kullanıcı: {row[0]}")
İleri Seviye Konular ve En İyi Uygulamalar
Daha sağlam ve güvenilir veritabanı etkileşimleri için bazı ileri seviye konuları ve en iyi uygulamaları bilmek önemlidir.
Hata Yönetimi ve İşlemler (Transactions)
Veritabanı işlemleri sırasında hatalar meydana gelebilir. Bu gibi durumlarda, veritabanının tutarlılığını sağlamak için işlemleri geri almak (rollback) önemlidir. Python’da try...except...finally blokları bu amaçla kullanılabilir. sqlite3 modülü, varsayılan olarak her execute() çağrısını bir işlem (transaction) içinde başlatır. commit() ile işlem onaylanır, rollback() ile geri alınır.
try:
# Hatalı bir sorgu çalıştırmaya çalışalım (örneğin, olmayan bir sütuna veri ekleme)
cursor.execute("INSERT INTO kullanicilar (ad, olmayan_sutun) VALUES (?, ?)",
("Deneme", "deger"))
conn.commit()
print("Hatalı ekleme başarılı oldu (beklenmedik).")
except sqlite3.Error as e:
print(f"\nHata yakalandı: {e}")
conn.rollback() # Hata durumunda değişiklikleri geri al
print("Değişiklikler geri alındı (rollback).")
finally:
# Bağlantıyı her zaman kapatmak için 'finally' bloğu kullanılır.
# Ancak, 'with' ifadesi daha güvenli bir yöntemdir.
# conn.close() # Şimdilik kapatmıyoruz, 'with' örneğine geçeceğiz.
pass
with İfadesi ile Kaynak Yönetimi (Context Manager)
sqlite3 bağlantı nesnesi, bir bağlam yöneticisi (context manager) olarak kullanılabilir. Bu, with ifadesi ile bağlantıyı açıp kapatmayı ve commit/rollback işlemlerini otomatik olarak yönetmeyi sağlar. Bu, en çok önerilen yaklaşımdır.
'with' ifadesi ile bağlantı yönetimi
try:
with sqlite3.connect('ornek_veritabani.db') as conn_with:
cursor_with = conn_with.cursor()
# Yeni bir tablo oluşturalım
cursor_with.execute('''
CREATE TABLE IF NOT EXISTS urunler (
id INTEGER PRIMARY KEY AUTOINCREMENT,
ad TEXT NOT NULL,
fiyat REAL NOT NULL
)
''')
print("\nUrunler tablosu 'with' ile oluşturuldu.")
# Veri ekleme
cursor_with.execute("INSERT INTO urunler (ad, fiyat) VALUES (?, ?)", ("Laptop", 1200.50))
cursor_with.execute("INSERT INTO urunler (ad, fiyat) VALUES (?, ?)", ("Mouse", 25.00))
print("Ürünler eklendi.")
# Bu noktada, 'with' bloğundan normal çıkışta otomatik olarak conn_with.commit() çağrılır.
# Eğer blok içinde bir hata oluşursa, otomatik olarak conn_with.rollback() çağrılır.
except sqlite3.Error as e:
print(f"Hata oluştu: {e}. Değişiklikler geri alındı.")
'with' bloğu dışında bağlantı otomatik olarak kapatılmış olur.
Şimdi verileri okuyabiliriz (yeni bir bağlantı açarak)
try:
with sqlite3.connect('ornek_veritabani.db') as conn_read:
cursor_read = conn_read.cursor()
print("\n--- 'with' ile eklenen Ürünler ---")
cursor_read.execute("SELECT ad, fiyat FROM urunler")
for row in cursor_read.fetchall():
print(f"Ürün: {row[0]}, Fiyat: {row[1]}")
except sqlite3.Error as e:
print(f"Veri okunurken hata oluştu: {e}")
row_factory Kullanımı
Varsayılan olarak, sqlite3 sorgu sonuçlarını tuple olarak döndürür. Sütunlara isimleriyle erişmek, kodun okunabilirliğini artırır. Bunu sağlamak için conn.row_factory = sqlite3.Row ayarını yapabilirsiniz. sqlite3.Row nesneleri, hem indeks hem de sütun ismi ile erişimi destekleyen tuple benzeri yapılardır.
with sqlite3.connect('ornek_veritabani.db') as conn_factory:
conn_factory.row_factory = sqlite3.Row # Bu satır çok önemli!
cursor_factory = conn_factory.cursor()
print("\n--- row_factory ile Kullanıcılar ---")
cursor_factory.execute("SELECT id, ad, email, yas FROM kullanicilar")
for row in cursor_factory.fetchall():
print(f"ID: {row['id']}, Ad: {row['ad']}, Email: {row['email']}, Yaş: {row['yas']}")
# Ayrıca indeks ile de erişebilirsiniz: print(f"Ad: {row[1]}")
Parametreli Sorguların Önemi
Daha önce de belirttiğimiz gibi, parametreli sorgular SQL enjeksiyon saldırılarını önlemek ve veri tiplerini otomatik olarak dönüştürmek için kritik öneme sahiptir. Kullanıcıdan gelen girdileri doğrudan SQL sorgusu içine birleştirmek yerine, her zaman ? (question mark) veya :param_adı (named parameter) gibi yer tutucular kullanın.
Güvenli (Parametreli) Sorgu
kullanici_adi = "Deneme"
kullanici_yasi = 40
cursor.execute("INSERT INTO kullanicilar (ad, email, yas) VALUES (?, ?, ?)",
(kullanici_adi, f"{kullanici_adi.lower()}@example.com", kullanici_yasi))
conn.commit()
Güvenli değil (SQL Injection riski var!)
kullanici_input = "Birisi'); DROP TABLE kullanicilar; --"
cursor.execute(f"INSERT INTO kullanicilar (ad) VALUES ('{kullanici_input}')")
ASLA BÖYLE KULLANMAYIN!
Sonuç ve Sıkça Sorulan Sorular (SSS)
sqlite3 modülü, Python uygulamalarınıza hafif ve güçlü bir veritabanı yeteneği eklemek için mükemmel bir araçtır. Bağlantı kurma, tablo oluşturma, CRUD operasyonları ve ileri düzey özellikler sayesinde, birçok senaryoda ihtiyaçlarınızı karşılayabilir. with ifadesini kullanarak kaynakları doğru yönetmek ve parametreli sorgularla güvenliği sağlamak, iyi bir uygulama geliştirmenin temelidir.
Sıkça Sorulan Sorular (SSS)
- SQLite nedir?
- SQLite, sunucusuz, kendi kendine yeten, sıfır yapılandırmalı, işlemsel bir SQL veritabanı motorudur. Bir dosya olarak depolanır ve harici bir sunucuya ihtiyaç duymaz.
- Neden Python’da
sqlite3kullanmalıyım? - Hafif, kurulum gerektirmeyen, Python’ın standart kütüphanesinin bir parçası olan ve küçük/orta ölçekli projeler, masaüstü uygulamaları veya testler için ideal bir veritabanı çözümüdür.
- Veritabanı dosyası nerede oluşur?
sqlite3.connect('veritabani.db')kullandığınızda,veritabani.dbdosyası, Python betiğinizin çalıştığı dizinde oluşur.- SQL injection saldırılarından nasıl korunurum?
- Her zaman parametreli sorgular kullanın. Kullanıcıdan gelen verileri doğrudan SQL sorgu dizelerine birleştirmek yerine,
?veya:param_adıgibi yer tutucular kullanarak verileri ayrı bir tuple veya dictionary olarak geçirin.sqlite3modülü bu verileri güvenli bir şekilde işleyecektir. - Yaptığım değişiklikler neden kaydedilmiyor?
- Veri manipülasyonu (INSERT, UPDATE, DELETE) veya tablo yapısı değişiklikleri (CREATE TABLE, ALTER TABLE) yaptıktan sonra
conn.commit()çağrısını yapmanız gerekir. Aksi takdirde, değişiklikler bellekte kalır ve bağlantı kapatıldığında kaybolur.withifadesini kullanmak, bu işlemi otomatik olarak yönetir. - Aynı anda birden fazla kullanıcı bir SQLite veritabanına erişebilir mi?
- Evet, ancak yüksek eşzamanlı yazma işlemleri için tasarlanmamıştır. Birden fazla okuyucu aynı anda erişebilirken, yazma işlemleri genellikle kilitlenir ve tek seferde sadece bir yazma işlemi gerçekleşebilir. Yüksek eşzamanlılık gerektiren uygulamalar için PostgreSQL veya MySQL gibi sunucu tabanlı veritabanları daha uygundur.
- Bellek içi veritabanı (
:memory:) ne işe yarar? sqlite3.connect(':memory:')ile oluşturulan veritabanları, sadece uygulamanızın çalıştığı süre boyunca bellekte tutulur ve bağlantı kapatıldığında tüm veriler kaybolur. Bu, özellikle testler veya geçici veri depolama için kullanışlıdır.