Ön Hazırlık ve Gereksinimler
Bu teknik rehberi takip edebilmek için temel düzeyde SQL bilgisine ve bir veritabanı yönetim sistemine (PostgreSQL, MySQL veya SQL Server) sahip olmanız gerekir. Örneklerimiz, endüstri standardı olan ANSI SQL sözdizimine dayanmaktadır.
- Veritabanı Motoru: PostgreSQL 16+ veya MySQL 8.4+ sürümü önerilir.
- Araçlar: DBeaver, pgAdmin veya komut satırı arayüzü (CLI).
- Bilgi Seviyesi: Tablo oluşturma (CREATE TABLE) ve kısıtlama (CONSTRAINT) mantığına aşinalık.
Temel Kısıtlamalar: NOT NULL ve UNIQUE Kullanımı
Veri kayıt kısıtlama kuralları arasında en sık kullanılanlar, sütunların boş geçilemez (NOT NULL) ve benzersiz (UNIQUE) olmasıdır. Bu kısıtlamalar, veritabanına hatalı kayıt girişini daha ilk aşamada reddeder.
Aşağıdaki örnekte, bir kullanıcı tablosu oluştururken e-posta adresinin benzersiz olması ve kullanıcı adının boş bırakılamaması kuralını tanımlıyoruz:
CREATE TABLE kullanicilar (
id SERIAL PRIMARY KEY,
kullanici_adi VARCHAR(50) NOT NULL,
eposta VARCHAR(100) UNIQUE NOT NULL,
kayit_tarihi TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);
Bu kod bloğunda NOT NULL ifadesi, ilgili sütuna veri girilmeden kayıt eklenmesini engeller. UNIQUE ise aynı e-posta adresiyle ikinci bir kayıt açılmasını veritabanı seviyesinde yasaklar.
CHECK Kısıtlaması ile Mantıksal Kurallar Koyma
CHECK kısıtlaması, bir sütuna girilen verinin belirli bir mantıksal koşulu sağlamasını zorunlu kılar. Örneğin, bir ürünün fiyatının sıfırdan küçük olamayacağını veya bir yaş sınırının belirli bir aralıkta olması gerektiğini bu yöntemle garanti altına alırsınız.
Aşağıdaki örnekte, ürün fiyatının her zaman pozitif olması için bir kısıtlama ekliyoruz:
ALTER TABLE urunler
ADD CONSTRAINT chk_fiyat_pozitif
CHECK (fiyat > 0);
Bu kural, uygulama katmanında bir hata olsa dahi, veritabanına negatif bir fiyat değerinin yazılmasını imkansız hale getirir. Test etmek için INSERT INTO urunler (fiyat) VALUES (-10); komutunu çalıştırdığınızda veritabanı "Check constraint violation" hatası dönecektir.
Foreign Key (Yabancı Anahtar) ile İlişkisel Bütünlük
Veritabanı uygulamalarında tablolar arası ilişkileri korumak, veri kayıt kısıtlama kuralları arasında en önemlisidir. FOREIGN KEY, bir tablodaki verinin başka bir tablodaki geçerli bir kayda referans vermesini sağlar.
Aşağıdaki örnekte, siparişler tablosunun sadece geçerli bir kullanıcıya bağlanabileceğini tanımlıyoruz:
CREATE TABLE siparisler (
siparis_id SERIAL PRIMARY KEY,
kullanici_id INT,
tutar DECIMAL(10, 2),
CONSTRAINT fk_kullanici
FOREIGN KEY(kullanici_id)
REFERENCES kullanicilar(id)
ON DELETE CASCADE
);
ON DELETE CASCADE ifadesi, bir kullanıcı silindiğinde ona ait tüm siparişlerin de otomatik olarak temizlenmesini sağlar. Bu, veritabanınızda "yetim kayıtlar" (orphan records) oluşmasını engeller.
Veri Kısıtlama Yöntemlerinin Karşılaştırması
Aşağıdaki tablo, farklı kısıtlama yöntemlerinin kullanım amaçlarını ve avantajlarını özetlemektedir:
| Kısıtlama Türü | Amacı | Avantajı |
|---|---|---|
| NOT NULL | Boş veri girişini engeller | Veri bütünlüğü sağlar |
| UNIQUE | Tekrarlanan veriyi engeller | Mükerrer kaydı önler |
| CHECK | Mantıksal aralıkları denetler | Veri kalitesini korur |
| FOREIGN KEY | İlişkisel tutarlılığı sağlar | İlişkili veriyi kontrol eder |
Güvenlik Uyarısı: Veritabanı kısıtlamaları, uygulamanızın son savunma hattıdır. SQL Injection saldırılarına karşı korunmak için her zaman parametreli sorgular (prepared statements) kullanın. Veritabanı kısıtlamaları, uygulama katmanındaki güvenlik önlemlerinin yerini tutmaz, onları tamamlar.
Trigger (Tetikleyici) ile Gelişmiş Kısıtlamalar
Bazen standart kısıtlamalar karmaşık iş mantığını karşılamaya yetmez. Bu durumlarda TRIGGER kullanarak kayıt anında daha detaylı kontroller yapabilirsiniz. Örneğin, bir kullanıcının günde en fazla 3 sipariş vermesini kısıtlamak isteyebilirsiniz.
CREATE OR REPLACE FUNCTION siparis_limiti_kontrol()
RETURNS TRIGGER AS $$
BEGIN
IF (SELECT COUNT(*) FROM siparisler WHERE kullanici_id = NEW.kullanici_id AND tarih = CURRENT_DATE) >= 3 THEN
RAISE EXCEPTION 'Günlük sipariş limitine ulaşıldı.';
END IF;
RETURN NEW;
END;
$$ LANGUAGE plpgsql;
CREATE TRIGGER trg_siparis_limiti
BEFORE INSERT ON siparisler
FOR EACH ROW EXECUTE FUNCTION siparis_limiti_kontrol();
Bu tetikleyici, her INSERT işleminden önce çalışır ve belirtilen mantıksal koşulu kontrol eder. Eğer koşul sağlanmıyorsa, veritabanı işlemi iptal eder.
Sıkça Sorulan Sorular
Veritabanı kısıtlamaları performansı düşürür mü?
Küçük ölçekli kısıtlamalar (NOT NULL, UNIQUE) performans üzerinde ihmal edilebilir bir etkiye sahiptir. Ancak çok karmaşık tetikleyiciler (triggers) yoğun yazma işlemlerinde gecikmeye neden olabilir; bu yüzden tetikleyicileri dikkatli kullanmalısınız.
Uygulama katmanındaki kontroller yeterli değil mi?
Uygulama katmanındaki kontroller kullanıcı deneyimi için gereklidir, ancak veritabanı kısıtlamaları verinin doğruluğunu garanti eden tek "gerçek" kaynaktır. Doğrudan veritabanına erişen diğer servisler için de bu kurallar geçerli kalır.
Kısıtlamaları test ederken nelere dikkat etmeliyim?
Kısıtlamaları test ederken "mutlu yol" (geçerli veriler) ve "hata yolu" (geçersiz veriler) senaryolarını ayrı ayrı çalıştırmalısınız. Hata durumunda veritabanının döndürdüğü hata mesajlarını uygulamanızda yakalayıp kullanıcıya anlamlı bir şekilde göstermelisiniz.
Var olan bir tabloya kısıtlama ekleyebilir miyim?
Evet, ALTER TABLE komutu ile tabloya sonradan CHECK veya FOREIGN KEY kısıtlamaları ekleyebilirsiniz. Ancak mevcut verilerin kısıtlamaya uygun olduğundan emin olmalısınız, aksi takdirde kısıtlama ekleme işlemi hata verecektir.
Hangi durumlarda kısıtlama kullanmamalıyım?
Sık değişen iş mantıkları için veritabanı kısıtlamaları yerine uygulama katmanı kontrolleri tercih edilebilir, çünkü veritabanı şemasını değiştirmek uygulama kodunu değiştirmekten daha zahmetli olabilir.
Veri Kısıtlama Hatalarını Yönetme ve Debugging Stratejileri
Veritabanı kısıtlamaları (constraints) devreye girdiğinde, uygulama katmanında genellikle SQLException veya benzeri bir hata fırlatılır. Bu hataları kullanıcıya anlamlı bir mesaj olarak döndürmek, hem kullanıcı deneyimi hem de sistemin güvenliği için kritiktir. Hatalı veri girişlerini izlemek ve kök nedeni bulmak için şu adımları izleyebilirsiniz:
Hata Kodlarını Yakalama ve Anlamlandırma
Veritabanı motorları, ihlal edilen kısıtlamalar için özel hata kodları üretir. Örneğin, PostgreSQL'de 23505 hata kodu unique_violation durumunu temsil eder. Uygulamanızda bu kodları yakalayarak kullanıcıya "Bu e-posta zaten kayıtlı" gibi özel mesajlar gösterebilirsiniz.
-- Örnek: Hata yakalama mantığı (Pseudo-code)
TRY {
INSERT INTO users (email) VALUES ('test@example.com');
} CATCH (DatabaseException e) {
IF (e.getErrorCode() == '23505') {
PRINT "Bu e-posta adresi sistemimizde zaten mevcut.";
}
}
Kısıtlama İhlallerini Loglama
Kısıtlama ihlalleri, genellikle uygulamanızdaki bir mantık hatasına veya kötü niyetli bir veri girişine işaret eder. Bu nedenle, veritabanı seviyesinde reddedilen her işlemi loglamak, sistemin zayıf noktalarını tespit etmenize yardımcı olur.
Karmaşık İş Mantığı İçin "Constraint Validation" Senaryosu
Bazen kısıtlamalar tek bir sütunla sınırlı kalmaz; birden fazla tablonun veya karmaşık iş kurallarının birleşimi gerekebilir. Örneğin, bir "E-Ticaret" sisteminde, bir kullanıcının aynı anda sadece bir "aktif" sepeti olabileceğini garanti etmek isteyebilirsiniz.
Bu tür senaryolarda standart kısıtlamalar yetersiz kalabilir. Bunun yerine, Partial Unique Index (Kısmi Benzersiz İndeks) kullanarak veritabanı seviyesinde kesinlik sağlayabilirsiniz:
-- Sadece 'active' durumu 'true' olan sepetler için benzersizlik kuralı
CREATE UNIQUE INDEX idx_unique_active_cart
ON carts (user_id)
WHERE status = 'active';
Bu yöntem, status = 'active' olan kayıtların user_id bazında benzersiz olmasını zorunlu kılar. Ancak, status = 'completed' veya status = 'cancelled' olan kayıtlar için bu kısıtlama devre dışı kalır. Bu sayede, veritabanı seviyesinde performansı düşürmeden iş mantığınızı korumuş olursunuz.
İleri Düzey İpuçları
- Deferred Constraints: Eğer karmaşık işlemlerinizde kısıtlamaların işlem (transaction) sonunda kontrol edilmesini istiyorsanız
DEFERRABLEözelliğini kullanın. Bu, döngüsel bağımlılıkları olan tablolarda veri girişi yapmanızı sağlar. - Constraint İsimlendirme: Kısıtlamalarınıza mutlaka anlamlı isimler verin (Örn:
fk_order_customer). Hata mesajlarında sistem tarafından atanan rastgele isimler yerine kendi tanımladığınız isimleri görmek, hata ayıklamayı %50 hızlandırır. - Test Odaklı Geliştirme: Kısıtlamalarınızı "Unit Test" seviyesinde test edin. Hatalı veri gönderildiğinde veritabanının reddettiğini doğrulayan testler yazmak, gelecekteki şema değişikliklerinde sistemin kırılmasını önler.
Profesyonel Not: Veritabanı kısıtlamaları, uygulamanızın son savunma hattıdır. Asla sadece uygulama katmanındaki validasyonlara güvenmeyin; veritabanı her zaman "doğru" olanın tek kaynağı (Single Source of Truth) kalmalıdır.
Sonuç
Sql & Veritabanı ile uygulamalar için veri kayıt kısıtlama kuralları, verinizin uzun vadeli sağlığı için vazgeçilmezdir. NOT NULL, UNIQUE, CHECK ve FOREIGN KEY gibi araçları kullanarak uygulamanızın temelini sağlamlaştırabilirsiniz. Unutmayın ki, veritabanı seviyesinde alınan önlemler, uygulamanızı dış etkenlerden ve hatalı veri girişlerinden koruyan en güçlü kalkanınızdır.
Bir sonraki adım olarak, veritabanı indeksleme (indexing) stratejilerini inceleyerek kısıtlamalarınızın performansını nasıl optimize edebileceğinizi öğrenebilirsiniz. İyi kodlamalar dilerim.
Sorumluluk Reddi: Bu rehberde yer alan SQL kodları genel eğitim amaçlıdır. Üretim ortamında (production) herhangi bir şema değişikliği yapmadan önce veritabanınızı yedeklemeniz ve değişiklikleri önce geliştirme/test ortamlarında doğrulamanız şiddetle önerilir.


Yorumlar (0)
Yorum Yaz