Bölüm 10: Veri Tabanı

Bölüm 10: Veri Tabanı · Çalışma Soruları
Veri tabanıİlişkisel modelSQLiteSQLJDBCResultSetPreparedStatementMySQLİşlemler
Sercan KÜLCÜ

Çoktan Seçmeli · Veri Tabanı Kavramı

Soru 1: Dosya mı, Veri Tabanı mı?

Bir okulun not kayıtları CSV dosyasında tutuluyor. Aynı anda birçok öğretmenin not girmeye başlamasıyla en çok hangi sorun veri tabanına geçmeyi gerektirir?

B: Düz dosyada iki program aynı anda yazarsa biri ötekinin değişikliğini ezebilir ya da dosya yarım kalabilir; veri tabanı kilitleme ve işlemlerle (ya hepsi ya hiçbiri) bunu yönetir. Dosyalar da kalıcıdır; CSV Java'dan BufferedReader ile okunabilir ve 1 MB gibi bir sınır yoktur.

Çoktan Seçmeli · Veri Tabanı Kavramı

Soru 2: Tablo, Satır, Birincil Anahtar

ogrenciler(no INTEGER PRIMARY KEY, ad TEXT, bolum TEXT) tablosu için hangisi doğrudur?

C: Satır bir varlığın (bir öğrenci) bütün bilgisidir, sütun bir özelliğidir (ad TEXT). Birincil anahtar her satırı benzersiz tanımlar: aynı no ile ikinci satır reddedilir. Benzersizlik başka sütunlara kendiliğinden geçmez; bunun için UNIQUE kısıtı yazılır. Java benzetmesi: tablo ≈ sınıf, sütun ≈ alan, satır ≈ nesne.

Çoktan Seçmeli · SQLite

Soru 3: SQLite'ın Özellikleri

SQLite için hangisi doğrudur?

D: SQLite gömülü ve sunucusuzdur: projeye tek bir sürücü jar'ı eklenir, jdbc:sqlite:okul.db dosyayı yoksa oluşturur. Bellekte geçici veri tabanı yalnızca jdbc:sqlite::memory: ile açılır. Aynı anda tek yazıcıya izin verdiği için çok kullanıcılı büyük sistemlerde MySQL, PostgreSQL gibi sunucu tabanlı sistemler tercih edilir.

Adım Adım Çalıştırma · SQL Temelleri

Soru 4: SQL Komutları ve id

Boş bir veri tabanında bu SQL komutları sırayla çalışıyor. Her komuttan sonra tablo nasıl olur, son SELECT ne döndürür?

idadfiyat

Tablo oluştu; üç sütun, hiç satır yok.

idadfiyat1kalem10

id verilmedi: INTEGER PRIMARY KEY en büyük id + 1 = 1 atar.

idadfiyat1kalem102defter253silgi5

defter id 2, silgi id 3 alır.

idadfiyat1kalem202defter253silgi10

WHERE fiyat < 20 iki satırı seçer (10 ve 5); ikisi de iki katına çıkar. defter (25) değişmez.

idadfiyat1kalem202defter25

id = 3 olan silgi silinir.

idadfiyat1kalem202defter253cetvel15

En büyük id artık 2: cetvel id 3'ü alır. Silinen satırın numarası yeniden kullanıldı (AUTOINCREMENT yazılsaydı 4 olurdu).

idadfiyat1kalem202defter253cetvel15

SELECT yalnızca okur; üç satır döner.

CREATE TABLE urun (id INTEGER PRIMARY KEY,
  ad TEXT, fiyat INTEGER);
INSERT INTO urun(ad, fiyat) VALUES ('kalem', 10);
INSERT INTO urun(ad, fiyat) VALUES ('defter', 25);
INSERT INTO urun(ad, fiyat) VALUES ('silgi', 5);
UPDATE urun SET fiyat = fiyat * 2 WHERE fiyat < 20;
DELETE FROM urun WHERE id = 3;
INSERT INTO urun(ad, fiyat) VALUES ('cetvel', 15);
SELECT * FROM urun;

Çoktan Seçmeli · SQL Temelleri

Soru 5: Süz, Sırala, Sınırla

ogrenci(ad, puan) tablosunda (Ece, 85), (Can, 70), (Ada, 85), (Efe, 65), (Naz, 92) var. Sorgu hangi adları hangi sırayla döndürür?

SELECT ad FROM ogrenci
WHERE puan >= 70
ORDER BY puan DESC, ad
LIMIT 3;

A: WHERE puan >= 70 Efe'yi eler. ORDER BY puan DESC büyükten küçüğe sıralar: Naz (92), sonra 85'teki iki kişi; eşitlikte ikinci ölçüt ad artan sırada: Ada, Ece. LIMIT 3 ilk üç satırı alır, Can (70) dışarıda kalır.

Çıktı Sorusu · SQL Temelleri

Soru 6: Toplama Fonksiyonları

ogrenci(ad, puan) tablosunda (Ece 85, Can 70, Ada 85, Efe 65, Naz 92) satırları var. Bu sorgu hangi dört değeri döndürür?

SELECT COUNT(*), AVG(puan),
       MAX(puan), MIN(puan)
FROM ogrenci
WHERE puan < 90;
Cevabı göster
4 | 76.25 | 85 | 65

WHERE önce satırları süzer: 92 puanlı Naz elenir, 4 satır kalır (85, 70, 85, 65). Toplama fonksiyonları bu satırlar üzerinde çalışır: COUNT 4, AVG = 305 / 4 = 76.25, MAX 85, MIN 65. Sonuç tek satırdır.

Çoktan Seçmeli · JDBC

Soru 7: Kaynakların Kapanma Sırası

try (Connection conn = ...; Statement st = conn.createStatement(); ResultSet rs = st.executeQuery(sql)) { ... } bloğu bitince kaynaklar hangi sırayla kapanır?

B: try-with-resources kaynakları açıldıkları sıranın tersiyle kapatır; blok istisnayla bitse de kapatma yapılır. ResultSet, Statement'a; Statement, Connection'a bağlı olduğu için bu sıra doğal olanıdır. Kapatılmayan bağlantılar SQLite dosyasını kilitli bırakabilir.

Çıktı Sorusu · Temel İşlemler

Soru 8: execute Metotlarının Dönüş Değerleri

t(id INTEGER PRIMARY KEY, ad TEXT) tablosu boş. Program ne yazdırır?

int a = st.executeUpdate(
  "INSERT INTO t(ad) VALUES ('x'), ('y'), ('z')");
int b = st.executeUpdate(
  "UPDATE t SET ad = 'w' WHERE id > 1");
int c = st.executeUpdate(
  "DELETE FROM t WHERE ad = 'q'");
boolean d = st.execute("SELECT * FROM t");
System.out.println(a + " " + b + " " + c + " " + d);
Cevabı göster
3 2 0 true
  • Tek INSERT üç satır ekler; executeUpdate etkilenen satır sayısını döndürür: 3 (id 1, 2, 3).
  • id > 1 iki satırı seçer: 2.
  • 'q' adlı satır yok: hata olmaz, 0 döner. Silme mesajını bu sayıya göre vermek bu yüzden doğrudur.
  • execute sonuç kümesi üreten komut için true, öteki komutlar için false döndürür.

Adım Adım Çalıştırma · Temel İşlemler

Soru 9: ResultSet ile Ortalama

kisiler tablosu şekildeki gibi. Program ne yazdırır? Ok, sonuç kümesindeki imleci gösterir.

kisileridadsoyadyas1AliKaya192EceDemir243CanKaya314NazDemir22sonuç kümesiadyasNaz22Ece24Can31

Sorgu çalışır: yas > 20 Ali'yi eler, kalanlar yaşa göre sıralanır. İmleç ilk satırdan önce bekler.

kisileridadsoyadyas1AliKaya192EceDemir243CanKaya314NazDemir22sonuç kümesiadyasNaz22Ece24Can31

rs.next() imleci 1. satıra taşır, true döner.

kisileridadsoyadyas1AliKaya192EceDemir243CanKaya314NazDemir22sonuç kümesiadyasNaz22Ece24Can31

Sütunlar adıyla okunur; sayaç ve toplam güncellenir.

kisileridadsoyadyas1AliKaya192EceDemir243CanKaya314NazDemir22sonuç kümesiadyasNaz22Ece24Can31

İkinci satır.

kisileridadsoyadyas1AliKaya192EceDemir243CanKaya314NazDemir22sonuç kümesiadyasNaz22Ece24Can31

Üçüncü satır.

kisileridadsoyadyas1AliKaya192EceDemir243CanKaya314NazDemir22sonuç kümesiadyasNaz22Ece24Can31

Başka satır yok: rs.next() false, döngü biter.

kisileridadsoyadyas1AliKaya192EceDemir243CanKaya314NazDemir22sonuç kümesiadyasNaz22Ece24Can31

77 / 3; (double) olmasaydı tam sayı bölmesi 25 verirdi. Blok bitince rs ve st kapanır.

String sql = "SELECT ad, yas FROM kisiler "
    + "WHERE yas > 20 ORDER BY yas";
try (Statement st = conn.createStatement();
     ResultSet rs = st.executeQuery(sql)) {
  int n = 0, toplam = 0;
  while (rs.next()) {
    String ad = rs.getString("ad");
    int yas = rs.getInt("yas");
    n++;
    toplam += yas;
    System.out.println(ad + " " + yas);
  }
  System.out.println(n + " kişi, ortalama "
      + (double) toplam / n);
}

Hata Bulma · Temel İşlemler

Soru 10: Üç Hata

kisiler(id, ad, soyad, yas) tablosuyla çalışan bu satırların her biri bir SQLException fırlatıyor. Nedenlerini ve düzeltmelerini yazın.

ResultSet rs = st.executeQuery(
    "SELECT ad FROM kisiler");
rs.next();
String ad = rs.getString(0);              // 1

st.executeQuery("INSERT INTO kisiler(ad, soyad, yas) "
    + "VALUES ('Ece', 'Er', 20)");          // 2

st.executeUpdate("INSERT INTO kisiler(ad, soyad, yas) "
    + "VALUES (Bora, 'Er', 20)");           // 3
Cevabı göster
  1. getString(0): sütun numaraları 1'den başlar. İleti: column 0 out of bounds [1,1]. Doğrusu getString(1) ya da getString("ad").
  2. INSERT sonuç kümesi döndürmez: query does not return ResultSet. INSERT, UPDATE, DELETE için executeUpdate kullanılır. (SQLite sürücüsüyle denemede satır yine de eklendi.)
  3. Bora tırnaksız yazıldığı için sütun adı sanılır: no such column: Bora. Metin değerler tek tırnak içinde yazılır; en iyisi PreparedStatement ve setString.

Çoktan Seçmeli · PreparedStatement

Soru 11: Yer Tutucuların Sırası

conn.prepareStatement("UPDATE kisiler SET yas = ? WHERE ad = ? AND soyad = ?") ile Ece Demir'in yaşı 25 yapılacak. Hangi çağrılar doğrudur?

C: ?'ler SQL metnindeki sıralarına göre 1'den başlayarak numaralanır: önce SET'teki yaş, sonra WHERE'deki ad ve soyad. 0 indisi geçersizdir. Her ? tek bir değerdir; ad ve soyadı tek parametrede birleştirmek eşleşmeyi bozar. Sonra executeUpdate() parametresiz çağrılır.

Çıktı Sorusu · PreparedStatement

Soru 12: Sayısal Enjeksiyon

k2 tablosunda id'si 1, 2, 3 olan üç satır var. Kullanıcı silinecek kayıt numarası olarak 0 OR 1=1 yazıyor. Önce PreparedStatement, sonra birleştirilmiş SQL çalışıyor. Hangi iki sayı yazdırılır?

String girdi = "0 OR 1=1";
try (PreparedStatement ps = conn.prepareStatement(
    "DELETE FROM k2 WHERE id = ?")) {
  ps.setString(1, girdi);
  System.out.println(ps.executeUpdate());
}
System.out.println(st.executeUpdate(
    "DELETE FROM k2 WHERE id = " + girdi));
Cevabı göster
0
3

PreparedStatement'ta girdi yalnızca bir değerdir: id = '0 OR 1=1' hiçbir satırla eşleşmez, 0 satır silinir.

Birleştirmede girdi SQL'in parçası olur: DELETE FROM k2 WHERE id = 0 OR 1=1. 1=1 her satırda doğru olduğu için tablonun tamamı silinir: 3. Enjeksiyon için tırnak gerekmez; sayısal alanlar da korunmalıdır. Girdi her zaman ? ve setXxx ile verilmelidir.

Kod Yazma · PreparedStatement

Soru 13: Soyada Göre Ortalama Yaş

static double ortalamaYas(Connection conn, String soyad) throws SQLException metodunu yazın: verilen soyadlı kişilerin yaş ortalamasını AVG ile bulup döndürsün; girdi SQL metnine eklenmesin, açılan kaynaklar kapansın. kisiler tablosunda Ali Kaya 19, Ece Demir 24, Can Kaya 31, Naz Demir 22 varken "Kaya" ve "Yok" için ne döner?

Cevabı göster
static double ortalamaYas(Connection conn, String soyad)
    throws SQLException {
  String sql = "SELECT AVG(yas) FROM kisiler WHERE soyad = ?";
  try (PreparedStatement ps = conn.prepareStatement(sql)) {
    ps.setString(1, soyad);
    try (ResultSet rs = ps.executeQuery()) {
      return rs.next() ? rs.getDouble(1) : 0;
    }
  }
}

"Kaya": (19 + 31) / 2 = 25.0. "Yok": eşleşen satır olmasa da AVG tek satır döndürür, değeri NULL'dır; getDouble NULL için 0.0 verir (ayırt etmek gerekirse rs.wasNull()). Bağlantı metodun parametresidir; onu açan kod kapatır.

Çoktan Seçmeli · MySQL

Soru 14: SQLite'tan MySQL'e

SQLite ile çalışan bir JDBC programı MySQL sunucusuna taşınacak. Genellikle neler değişir?

D: JDBC arayüzleri aynıdır; çok biçimlilik sayesinde gerçek nesneyi sürücü sağlar. Değişenler: jdbc:mysql://localhost:3306/testdb gibi adres, getConnection(url, kullanici, sifre) ve mysql-connector-j jar'ı. Temel SQL (CREATE, INSERT, SELECT…) büyük ölçüde aynıdır; küçük farklar (ör. otomatik artan anahtar sözdizimi) olabilir.

Çoktan Seçmeli · İşlemler

Soru 15: ACID

“Bir havale commit edildikten bir saniye sonra elektrik kesilse bile, sistem yeniden açıldığında havale yapılmış görünür.” Bu cümle ACID'in hangi özelliğidir?

A: Kalıcılık: commit edilen değişiklik kalıcı depolamaya yazılmıştır, kaybolmaz. Bölünmezlik işlemin ya tamamının ya hiçbirinin uygulanması; tutarlılık işlem sonunda kısıtların (ör. bakiye ≥ 0) sağlanması; yalıtım eş zamanlı işlemlerin birbirinin yarım hâlini görmemesidir.

Adım Adım Çalıştırma · İşlemler

Soru 16: UNIQUE Hatası ve rollback

uye(id INTEGER PRIMARY KEY, email TEXT UNIQUE) tablosu boş. Üç e-posta tek bir işlem içinde ekleniyor. Program ne yazdırır, tabloda kaç satır kalır? Kesikli satırlar henüz commit edilmemiştir.

idemail

İşlem başlar: bundan sonraki değişiklikler commit'e kadar geçicidir.

idemail1a@x

a@x eklenir (id 1), henüz kalıcı değil.

idemail1a@x2b@x

b@x eklenir (id 2).

idemail1a@x2b@x

a@x ikinci kez: UNIQUE constraint failed: uye.email. SQLException fırlar; commit satırına gelinmez.

idemail

rollback(): işlemdeki iki ekleme de geri alınır.

idemail

finally auto-commit'i yeniden açar. Tabloda 0 satır: ya hepsi ya hiçbiri.

conn.setAutoCommit(false);
String sql = "INSERT INTO uye(email) VALUES(?)";
try (PreparedStatement ps = conn.prepareStatement(sql)) {
  for (String e : new String[] {"a@x", "b@x", "a@x"}) {
    ps.setString(1, e);
    ps.executeUpdate();
  }
  conn.commit();
  System.out.println("kaydedildi");
} catch (SQLException ex) {
  conn.rollback();
  System.out.println("geri alındı");
} finally {
  conn.setAutoCommit(true);
}

Çıktı Sorusu · İşlemler

Soru 17: İşlem Olmadan

uye(id INTEGER PRIMARY KEY, email TEXT UNIQUE) tablosu boş ve bağlantı varsayılan ayarda (auto-commit açık). Kod çalıştıktan sonra tabloda kaç satır kalır, neden?

String sql = "INSERT INTO uye(email) VALUES(?)";
try (PreparedStatement ps = conn.prepareStatement(sql)) {
  for (String e : new String[] {"a@x", "b@x", "a@x"}) {
    ps.setString(1, e);
    ps.executeUpdate();
  }
} catch (SQLException ex) {
  System.out.println("hata");
}
Cevabı göster

2 satır (a@x ve b@x). Auto-commit açıkken her executeUpdate kendi başına kalıcı olur: ilk iki ekleme hemen yazılır, üçüncüsü UNIQUE yüzünden reddedilir ve geri alınacak bir işlem yoktur. Liste “ya hepsi ya hiçbiri” yerine yarım kalır. setAutoCommit(false), commit() ve hata durumunda rollback() ile tablo boş kalırdı. Birlikte anlam taşıyan komutlar (havale, sipariş ve kalemleri) bu yüzden tek işlemde yürütülür.

Son

Bölüm 10: Veri Tabanı: Çalışma Soruları
Konu anlatımı: Veri tabanı sunumu · Terim sözlüğü
1 / 1 Sercan KÜLCÜ, Tüm hakları saklıdır.