Bölüm 10: Veri Tabanı
Giriş
Öğrenme Çıktıları
Veritabanının neden gerektiğini, dosyalardan farkını ve ilişkisel modeli (tablo, satır, sütun, birincil anahtar) açıklamak.
CREATE TABLE, INSERT, SELECT, UPDATE, DELETE komutlarını yazmak; WHERE, ORDER BY, LIMIT ile sorguyu daraltmak.
Connection, Statement ve ResultSet ile Java'dan SQLite'a bağlanıp kayıt eklemek, okumak, güncellemek ve silmek; kaynakları try-with-resources ile kapatmak.
SQL enjeksiyonunu PreparedStatement ile önlemek; commit/rollback ile birden çok komutu tek bir işlem olarak yürütmek.
Veritabanı Kavramı
Veritabanı Neden Önemlidir?
- Programdaki değişkenler ve nesneler RAM'de yaşar: program kapanınca kaybolur.
- Kalıcı depolama (persistent storage): verinin uzun süre, program kapandıktan sonra da saklanması. Öğrenci notları, banka hesapları, oyun skorları hep kalıcı olmalıdır.
- Veritabanı (database): düzenli biçimde saklanan ve kolayca sorgulanabilen veri topluluğu. Onu yöneten yazılıma Veritabanı Yönetim Sistemi (VTYS, DBMS) denir.
- Benzetme: veritabanı, kütüphanenin kataloglu arşivi gibidir; aradığınız kitabı tüm rafları gezmeden bulursunuz.
Veritabanı Kavramı
Dosya mı, Veritabanı mı?
Dosya sistemleri bazı uygulamalar için yeterli olabilir (ayar dosyası, günlük kaydı, kısa bir liste). Veri büyüyüp karmaşıklaştıkça veritabanları gerekir: verinin verimli işlenmesi için önemli özellikler sunarlar.
| Özellik | Düz dosya (txt, csv) | Veritabanı |
|---|---|---|
| Arama | Dosya baştan sona okunur | İndeksle hızlı; tek satırlık SQL sorgusu |
| Güncelleme | Çoğu zaman tüm dosya yeniden yazılır | Yalnızca ilgili satır değişir |
| Eşzamanlı erişim | İki program aynı anda yazarsa veri bozulabilir | Kilitleme ve işlemlerle güvenli |
| Tutarlılık | Biçim denetimi tamamen programcıya kalır | Veri tipleri ve kısıtlar (NOT NULL, UNIQUE, CHECK) |
| Güvenlik | Dosya izni: ya hepsi ya hiçbiri | Kullanıcı, tablo ve alan düzeyinde yetki |
| Hata sonrası | Yarım kalan yazma dosyayı bozabilir | Yarım kalan işlem geri alınır |
Veritabanı Kavramı
Temel Özellikler
İndeksler sayesinde milyonlarca satır arasından aranan kayıt kısa sürede bulunur.
Yetki tablo, hatta sütun (alan) düzeyinde verilebilir: maaş sütununu yalnızca muhasebe birimi görebilir.
SQL bir standarttır; Java'da JDBC aynı arayüzle farklı veritabanlarına erişir.
Program verinin diskte nasıl tutulduğunu bilmez. Ne istediğini SQL ile söyler; nasıl bulunacağına VTYS karar verir.
Bunlara ek olarak veritabanları veri bütünlüğü kısıtları ve işlem (transaction) desteği sunar; bölümün sonunda göreceğiz.
Veritabanı Kavramı
İlişkisel Model: Tablo, Satır, Sütun
- İlişkisel (relational) veritabanı veriyi tablolarda saklar.
- Sütun: verinin bir özelliği; adı ve veri tipi vardır (
name TEXT). - Satır: bir varlığın tüm bilgileri (bir kullanıcı).
- Birincil anahtar: her satırı benzersiz tanımlar; iki satırın
id'si aynı olamaz. - Java benzetmesi: tablo ≈ sınıf, sütun ≈ alan, satır ≈ nesne.
Veritabanı Kavramı
Veritabanı Türleri
Tablolar ve SQL. Oracle, SQL Server, MySQL, PostgreSQL. Kullanımın büyük bölümü (yaklaşık %77).
Belge, anahtar–değer, arama dizini gibi tablosuz modeller; belirli senaryolarda kullanılır: MongoDB, Elasticsearch (yaklaşık %23).
SQLite: programın içinde çalışan ilişkisel veritabanı; veri paylaşımının az olduğu durumlarda yaygındır.
Bu bölümde, kurulumu en kolay olan SQLite'ı kullanacağız. Öğrendiğiniz SQL ve JDBC kodu diğer ilişkisel veritabanlarında da neredeyse aynıdır.
SQLite
SQLite Nedir?
- Gömülü (embedded) bir ilişkisel veritabanıdır: programın içinde bir kütüphane olarak çalışır.
- Sunucuya ihtiyaç duymaz (serverless): ayrı bir program, kurulum ya da yönetici gerekmez.
- Kendine yeten bir yapıya sahiptir: tüm tablolar tek bir disk dosyasında saklanır (ör.
sample.db). - Çapraz platform: aynı dosya Windows, Linux, macOS ve Android'de açılır.
- Kolayca kurulur ve kullanılır; açık kaynaklı ve ücretsizdir.
- Dünyada en yaygın kullanılan gömülü ilişkisel veritabanıdır.
Yaygın kullanım alanları
- Mobil uygulamalar
- Gömülü sistemler
- Küçük ölçekli uygulamalar
- Tarayıcı, e-posta istemcisi gibi masaüstü programları
Uygun olmadığı yer
- Ağ üzerinden çok sayıda kullanıcının aynı anda yazdığı büyük sistemler
SQLite
Sunucu Tabanlı ve Gömülü Veritabanı
| Sunucu tabanlı | SQLite | |
|---|---|---|
| Kurulum | Sunucu kurulur, kullanıcı ve şifre tanımlanır | Projeye tek bir jar eklenir |
| Veri | Sunucunun yönettiği birçok dosya | Tek bir .db dosyası |
| Eşzamanlı yazma | Çok kullanıcı | Aynı anda tek yazıcı |
SQLite
SQLite Sürücüsü ve DB Browser
Java'nın SQLite ile konuşmasını sağlayan jar dosyası (sqlite-jdbc-3.x.jar): github.com/xerial/sqlite-jdbc
SQLite için popüler bir SQL istemcisi: .db dosyasını açar, tabloları görsel gösterir, SQL çalıştırır: sqlitebrowser.org/dl
Eclipse'te sürücüyü projeye eklemek
- Jar dosyasını indirip projede bir
libklasörüne koyun. - Projeye sağ tık → Build Path → Configure Build Path…
- Libraries sekmesi → Classpath → Add JARs… → jar'ı seçin → Apply and Close.
Komut satırından
javac Baglan.java java -cp ".;sqlite-jdbc-3.40.0.0.jar" Baglan
Linux ve macOS'ta ayırıcı ; yerine : olur. Derleme için sürücü gerekmez; java.sql paketi JDK ile gelir.
SQL Temelleri
Yaygın SQL Komutları
| Komut | Görevi | Örnek | CRUD |
|---|---|---|---|
CREATE TABLE | Yeni tablo oluşturur | CREATE TABLE users (id INTEGER, name TEXT) | — |
INSERT INTO | Yeni kayıt ekler | INSERT INTO users(name) VALUES('Ali') | Create |
SELECT | Tabloyu sorgular | SELECT * FROM users | Read |
UPDATE | Var olan kayıtları günceller | UPDATE users SET name = 'Efe' WHERE id = 1 | Update |
DELETE | Kayıtları siler | DELETE FROM users WHERE id = 1 | Delete |
- SQL (Structured Query Language, yapılandırılmış sorgu dili): ilişkisel veritabanlarının ortak dilidir.
- Anahtar kelimelerde büyük/küçük harf fark etmez; okunabilirlik için BÜYÜK yazılır. Metin değerler tek tırnak içindedir:
'Ali'. *“tüm sütunlar” demektir.WHEREkomutun hangi satırlara uygulanacağını seçer.
SQL Temelleri
CREATE TABLE ve Veri Tipleri
CREATE TABLE IF NOT EXISTS uyeler ( id INTEGER PRIMARY KEY, -- benzersiz name TEXT NOT NULL, -- boş olamaz email TEXT UNIQUE, -- tekrar edemez yas INTEGER CHECK (yas >= 0) )
IF NOT EXISTS: tablo zaten varsa hata verme.INTEGER PRIMARY KEY: değer verilmezse SQLite en büyük id + 1 atar.- Kısıt bozulursa komut reddedilir:
NOT NULL constraint failed: uyeler.name,CHECK constraint failed: yas >= 0.
| SQLite tipi | Java karşılığı |
|---|---|
INTEGER | int, long · getInt |
REAL | double · getDouble |
TEXT | String · getString |
BLOB | byte[] · getBytes |
NULL | değer yok |
SQL Temelleri
SQL Komutları Adım Adım
CREATE TABLE users (id INTEGER PRIMARY KEY, name TEXT, email TEXT)
Tablo oluşturuldu: üç sütun var, henüz hiç satır yok.
INSERT INTO users(name, email) VALUES('Ahmet Yılmaz', 'ahmet@example.com')
id verilmedi; SQLite 1 atadı. 1 satır etkilendi.
INSERT INTO users(name, email) VALUES('Ayşe Demir', 'ayse@example.com')
İkinci kayıt id = 2 aldı (en büyük id + 1).
UPDATE users SET name = 'Mehmet Akdeniz' WHERE id = 1
WHERE id = 1 yalnızca ilk satırı seçti; sadece name değişti, email aynı kaldı.
DELETE FROM users WHERE id = 1
id = 1 olan satır silindi. 1 satır etkilendi.
SELECT * FROM users
Sorgu tabloyu değiştirmez, yalnızca okur: sonuç tek satır (2, Ayşe Demir, ayse@example.com).
SQL Temelleri
SELECT: Süzme, Sıralama, Sınırlama
| Sorgu | Sonuç |
|---|---|
SELECT oyuncu, puan FROM skorlar | naz 81, ada 72, ece 58 |
SELECT oyuncu, puan FROM skorlar | can 95, efe 95, naz 81 |
SELECT oyuncu, puan FROM skorlar | ece 58, efe 95 |
SELECT COUNT(*), AVG(puan), MAX(puan) | 4 · 85.75 · 95 |
WHEREsatırları süzer (=,<>,<,>=,AND,OR,LIKE 'e%': “e ile başlayan”).ORDER BY … DESCbüyükten küçüğe sıralar; eşitlikte ikinci ölçüt (oyuncu) kullanılır.LIMIT 3ilk 3 satırı alır.
JDBC
JDBC (Java Database Connectivity)
- JDBC (Java Database Connectivity): Java'nın veritabanlarına bağlanmak için sunduğu standart API'dir;
java.sqlpaketindedir ve JDK ile gelir. - Program yalnızca JDBC arayüzlerini kullanır; her veritabanı üreticisi bu arayüzleri gerçekleyen bir sürücü (driver) sağlar.
- Veritabanını değiştirmek için çoğu zaman yalnızca sürücü jar'ı ve bağlantı adresi değişir.
- Çok biçimlilik iş başında:
Connectionbir arayüzdür; SQLite'ta gerçek nesnenin sınıfıorg.sqlite.jdbc4.JDBC4Connection'dır.
JDBC
JDBC'nin Temel Türleri
| Tür | Görevi | Önemli metotlar |
|---|---|---|
DriverManager | Uygun sürücüyü bulur, bağlantı açar | getConnection(url), getConnection(url, kullanici, sifre) |
Connection | Veritabanıyla açık bir oturum | createStatement(), prepareStatement(sql), commit(), rollback(), close() |
Statement | Sabit bir SQL metnini çalıştırır | execute, executeUpdate, executeQuery |
PreparedStatement | ? yer tutuculu, önceden hazırlanan SQL | setInt, setString, executeUpdate(), executeQuery() |
ResultSet | Sorgu sonucundaki satırlar ve bir imleç | next(), getInt("id"), getString("name") |
SQLException | Veritabanı hatası; kontrol edilen istisna | getMessage(), getErrorCode() |
Hepsi java.sql paketindedir: dosyanın başına import java.sql.*; yazılır. Connection, Statement ve ResultSet kapatılması gereken kaynaklardır (AutoCloseable).
JDBC
Bağlantı Adresi (JDBC URL)
| Bağlantı adresi (URL) | Anlamı |
|---|---|
jdbc:sqlite:sample.db | Çalışma dizinindeki sample.db; yoksa boş olarak oluşturulur |
jdbc:sqlite:C:/veriler/okul.db | Tam yol ile dosya |
jdbc:sqlite::memory: | Bellekte geçici veritabanı; bağlantı kapanınca silinir (denemeler için) |
jdbc:mysql://localhost:3306/testdb | MySQL sunucusu: makine, port, veritabanı adı; ayrıca kullanıcı adı ve şifre |
- Biçim:
jdbc:<alt protokol>:<veritabanı_dosyanız veya adresi>.DriverManager, alt protokole bakarak sürücüyü seçer. - JDBC 4.0 (Java 6) ve sonrasında sürücü, classpath'teki jar'dan otomatik yüklenir. Eski kodlardaki
Class.forName("org.sqlite.JDBC")satırı artık gerekmez. - Sürücü classpath'te yoksa:
No suitable driver found for jdbc:sqlite:sample.db.
JDBC
Bir JDBC Programının Adımları
try (Connection conn = DriverManager.getConnection(url); // 1 Statement stmt = conn.createStatement(); // 2 ResultSet rs = stmt.executeQuery(sql)) { // 3 while (rs.next()) { // 4 System.out.println(rs.getInt(1)); } } // 5: rs, stmt, conn ters sırada otomatik kapanır
- Kaynaklar try-with-resources parantezinde açılır; blok bitince (hata olsa bile) ters sırada kapanır: önce
rs, sonrastmt, en sonconn. - Kapatılmayan bağlantılar dosyayı kilitli bırakabilir ve bellek sızıntısına yol açar.
getInt(1): sütun numaraları 1'den başlar.
Temel İşlemler
SQLite'a Bağlanma
// Veritabanı dosyasının yolu (bağlantı adresi) String url = "jdbc:sqlite:sample.db"; try (Connection conn = DriverManager.getConnection(url)) { // Bağlantı başarılıysa mesaj yazdırılır. if (conn != null) { System.out.println("Bağlantı başarılı!"); } } catch (SQLException e) { // Bağlantı hatası olursa hata mesajı yazdırılır. System.out.println(e.getMessage()); }
Bağlantı başarılı!
getConnectiondosya yoksa oluşturur (boş veritabanı).- Bağlantı kurulamazsa
nulldönmez,SQLExceptionfırlatır;if (conn != null)yalnızca ek bir güvencedir. SQLExceptionkontrol edilen istisnadır: yakalanmalı ya dathrowsile bildirilmelidir.
Temel İşlemler
Tablo Oluşturma
String url = "jdbc:sqlite:sample.db";
String sql = "CREATE TABLE IF NOT EXISTS users "
+ "(id INTEGER PRIMARY KEY, name TEXT, email TEXT)";
try (Connection conn = DriverManager.getConnection(url);
Statement stmt = conn.createStatement()) {
// Tablo oluşturuluyor.
stmt.execute(sql);
System.out.println("Tablo oluşturuldu!");
} catch (SQLException e) {
System.out.println(e.getMessage());
}Tablo oluşturuldu!
execute(sql)her tür SQL'i çalıştırır; sonuç kümesi üretirsetrue,CREATEiçinfalsedöner.IF NOT EXISTSsayesinde program ikinci kez çalışınca hata olmaz. Olmasaydı:table users already exists.- Birden çok kaynak tek
try (…; …)içinde;ile ayrılır.
Temel İşlemler
Veri Ekleme
String url = "jdbc:sqlite:sample.db";
String sql = "INSERT INTO users(name, email) "
+ "VALUES('Ahmet Yılmaz', 'ahmet@example.com')";
try (Connection conn = DriverManager.getConnection(url);
Statement stmt = conn.createStatement()) {
// Veritabanına veri ekleniyor.
int sayi = stmt.executeUpdate(sql);
System.out.println("Veri eklendi! (" + sayi + " satır)");
} catch (SQLException e) {
System.out.println(e.getMessage());
}Veri eklendi! (1 satır)
executeUpdateetkilenen satır sayısını (int) döndürür.idverilmedi; SQLite1atadı.- Program her çalıştığında yeni bir satır eklenir (id 2, 3, …).
- SQL içindeki metin değerler tek tırnak içindedir.
Temel İşlemler
Veri Okuma
String url = "jdbc:sqlite:sample.db"; String sql = "SELECT * FROM users"; try (Connection conn = DriverManager.getConnection(url); Statement stmt = conn.createStatement(); ResultSet rs = stmt.executeQuery(sql)) { // Satırlar tek tek okunup yazdırılıyor. while (rs.next()) { System.out.println("ID: " + rs.getInt("id") + ", Ad: " + rs.getString("name") + ", E-posta: " + rs.getString("email")); } } catch (SQLException e) { System.out.println(e.getMessage()); }
ID: 1, Ad: Ahmet Yılmaz, E-posta: ahmet@example.com
executeQuerybirResultSetdöndürür.rs.next()imleci bir sonraki satıra taşır; satır varsatrue, yoksafalsedöner.getInt("id"),getString("name"): o anki satırın sütunlarını adıyla okur.
Temel İşlemler
ResultSet ile Okuma: Adım Adım
Bağlantı açılır, sorgu çalışır. rs iki satırlık sonucu tutar; imleç ilk satırdan önce bekler.
rs.next() imleci 1. satıra taşır ve true döndürür: döngüye girilir.
Sütunlar o anki satırdan okunur.
Satır yazdırılır.
İmleç 2. satıra geçer; yine true.
Bu kez 2. satırın değerleri okunur.
İkinci satır yazdırılır.
Başka satır yok: rs.next() false döner, döngü biter.
Döngüden sonraki satır çalışır.
try bloğu biter: rs, stmt, conn bu sırayla otomatik kapanır.
String url = "jdbc:sqlite:okuma.db"; String sql = "SELECT * FROM users"; try (Connection conn = DriverManager.getConnection(url); Statement stmt = conn.createStatement(); ResultSet rs = stmt.executeQuery(sql)) { while (rs.next()) { int id = rs.getInt("id"); String ad = rs.getString("name"); System.out.println(id + " - " + ad); } System.out.println("Okuma bitti."); } catch (SQLException e) { System.out.println(e.getMessage()); }
Temel İşlemler
Veri Güncelleme
String url = "jdbc:sqlite:sample.db"; String sql = "UPDATE users SET name = 'Mehmet Akdeniz' WHERE id = 1"; try (Connection conn = DriverManager.getConnection(url); Statement stmt = conn.createStatement()) { // Veritabanındaki veri güncelleniyor. int sayi = stmt.executeUpdate(sql); System.out.println("Veri güncellendi! (" + sayi + " satır)"); } catch (SQLException e) { System.out.println(e.getMessage()); }
Veri güncellendi! (1 satır)
- Öncesinde okuma:
ID: 1, Ad: Ahmet Yılmaz, …; sonrasında:ID: 1, Ad: Mehmet Akdeniz, … SETyalnızca yazılan sütunu değiştirir;emailaynı kalır.WHERE id = 1güncellenecek satırı seçer. WHERE unutulursa tüm satırlar güncellenir.
Temel İşlemler
Veri Silme
String url = "jdbc:sqlite:sample.db"; String sql = "DELETE FROM users WHERE id = 1"; try (Connection conn = DriverManager.getConnection(url); Statement stmt = conn.createStatement()) { // Veritabanındaki veri siliniyor. int sayi = stmt.executeUpdate(sql); System.out.println("Veri silindi! (" + sayi + " satır)"); } catch (SQLException e) { System.out.println(e.getMessage()); }
Veri silindi! (1 satır) Veri silindi! (0 satır)
- İkinci çalıştırmada silinecek satır kalmamıştır: hata oluşmaz,
executeUpdate0döner. - Bu yüzden mesajı dönen sayıya göre vermek daha doğrudur (Alıştırma 1).
- WHERE'siz
DELETE FROM userstüm satırları siler; tablonun kendisi kalır.
Temel İşlemler
execute, executeUpdate, executeQuery
| Metot | Döndürür | Kullanım |
|---|---|---|
execute | boolean | CREATE TABLE, DROP |
executeUpdate | int satır sayısı | INSERT, UPDATE, DELETE |
executeQuery | ResultSet | SELECT |
Yanlış metot hataya yol açar: executeQuery ile INSERT çalıştırmak → query does not return ResultSet.
> java Baglan Bağlantı başarılı! > java TabloOlustur Tablo oluşturuldu! > java VeriEkle Veri eklendi! (1 satır) > java VeriOku ID: 1, Ad: Ahmet Yılmaz, E-posta: ahmet@example.com > java VeriGuncelle Veri güncellendi! (1 satır) > java VeriOku ID: 1, Ad: Mehmet Akdeniz, E-posta: ahmet@example.com > java VeriSil Veri silindi! (1 satır) > java VeriOku > java VeriSil Veri silindi! (0 satır)
PreparedStatement
SQL Enjeksiyonu (SQL Injection)
String girdi = "x' OR '1'='1"; // kullanıcının yazdığı "ad" // TEHLİKELİ: girdi SQL metnine yapıştırılıyor String sql = "SELECT ad FROM kisiler WHERE ad = '" + girdi + "'"; System.out.println(sql); ResultSet rs1 = stmt.executeQuery(sql); // GÜVENLİ: girdi yalnızca değer olarak gönderiliyor PreparedStatement ps = conn.prepareStatement( "SELECT ad FROM kisiler WHERE ad = ?"); ps.setString(1, girdi); ResultSet rs2 = ps.executeQuery();
SELECT ad FROM kisiler WHERE ad = 'x' OR '1'='1' Birleştirme: 3 satır PreparedStatement: 0 satır
- Kullanıcının yazdığı tırnak, SQL metnini değiştirdi:
'1'='1'her zaman doğru, tüm satırlar döndü. - Giriş ekranında bu, şifresiz oturum açmak demektir.
?ile gönderilen girdi yalnızca bir değerdir; SQL'in parçası olamaz.
PreparedStatement
PreparedStatement ve Yer Tutucular
static void ekle(Connection conn, String ad, String soyad, int yas) throws SQLException { String sql = "INSERT INTO kisiler(ad, soyad, yas) " + "VALUES(?, ?, ?)"; try (PreparedStatement ps = conn.prepareStatement(sql)) { ps.setString(1, ad); // 1. soru işareti ps.setString(2, soyad); // 2. soru işareti ps.setInt(3, yas); // 3. soru işareti ps.executeUpdate(); } }
Neden?
- Güvenli: SQL enjeksiyonunu önler.
- Tırnak sorunu yok:
"Ali'nin"sorunsuz kaydedilir. - Aynı komut farklı değerlerle tekrar kullanılır.
setXxx(sıra, değer) her ?'i doldurur; sıra 1'den başlar. Sonra executeUpdate() parametresiz çağrılır.
PreparedStatement
Kişi Programı: Güncelleme ve Silme Metotları
static void guncelle(Connection conn, String ad, String soyad, int yas) throws SQLException { String sql = "UPDATE kisiler SET soyad = ?, yas = ? " + "WHERE ad = ?"; try (PreparedStatement ps = conn.prepareStatement(sql)) { ps.setString(1, soyad); ps.setInt(2, yas); ps.setString(3, ad); ps.executeUpdate(); } } static void sil(Connection conn, String ad) throws SQLException { String sql = "DELETE FROM kisiler WHERE ad = ?"; try (PreparedStatement ps = conn.prepareStatement(sql)) { ps.setString(1, ad); ps.executeUpdate(); } }
- Her metot
Connection'ı parametre olarak alır: bağlantı bir kez açılır, birçok işte kullanılır. ?'ler SQL'deki sıraya göre numaralanır:guncelle'de ad, 3. yer tutucudur.throws SQLException: hata çağırana iletilir;maindethrowsile bildirdiğinden hata olursa program yığın iziyle durur.
PreparedStatement
Kişi Programı: Listeleme Metodu
static void listele(Connection conn) throws SQLException { String sql = "SELECT id, ad, soyad, yas FROM kisiler"; try (Statement st = conn.createStatement(); ResultSet rs = st.executeQuery(sql)) { while (rs.next()) { System.out.println(rs.getInt("id") + " " + rs.getString("ad") + " " + rs.getString("soyad") + " " + rs.getInt("yas")); } System.out.println("---"); } }
1 Ahmet Akdeniz 35 2 Ayşe Demir 40 ---
- Sorguda değişken değer olmadığından düz
Statementyeterlidir. - Her
listeleçağrısı tablonun o anki hâlini okur; sonuna---yazar.
PreparedStatement
Kişi Programı: Adım Adım
kisiler.db yoksa oluşturulur; bağlantı ve stmt açılır.
Tablo oluşturulur; henüz boştur.
ekle: ?'ler doldurulur, satır eklenir, id = 1.
İkinci kişi id = 2 ile eklenir.
WHERE ad = ?: Ahmet'in soyadı ve yaşı değişir.
listele tüm satırları ve --- yazar.
Ahmet'in satırı silinir.
Tabloda yalnızca Ayşe kaldı.
Bağlantı kapanır; veri kisiler.db'de kalıcıdır.
public static void main(String[] args) throws SQLException { String url = "jdbc:sqlite:kisiler.db"; try (Connection conn = DriverManager.getConnection(url); Statement stmt = conn.createStatement()) { stmt.execute("CREATE TABLE IF NOT EXISTS kisiler (" + "id INTEGER PRIMARY KEY, ad TEXT NOT NULL, " + "soyad TEXT NOT NULL, yas INTEGER NOT NULL)"); ekle(conn, "Ahmet", "Yılmaz", 30); ekle(conn, "Ayşe", "Demir", 40); guncelle(conn, "Ahmet", "Akdeniz", 35); listele(conn); sil(conn, "Ahmet"); listele(conn); } }
MySQL
Aynı Kod, Başka Veritabanı: MySQL
String url = "jdbc:mysql://localhost:3306/testdb"; String kullanici = "root"; String sifre = "sifreniz"; String sql = "SELECT id, name, email FROM users"; try (Connection conn = DriverManager.getConnection(url, kullanici, sifre); Statement stmt = conn.createStatement(); ResultSet rs = stmt.executeQuery(sql)) { while (rs.next()) { System.out.println(rs.getInt("id") + " " + rs.getString("name")); } } catch (SQLException e) { System.out.println(e.getMessage()); }
- JDBC kodu aynıdır; değişenler: adres, kullanıcı adı, şifre ve sürücü jar'ı (
mysql-connector-j). - MySQL bir sunucudur: önce kurulup çalıştırılmalı,
testdbveritabanı oluşturulmalıdır. - Sürücü sınıfı
com.mysql.cj.jdbc.Driver'dır; eskicom.mysql.jdbc.Driveradı kullanımdan kalkmıştır. - Gerçek projelerde şifre koda yazılmaz; ayar dosyasından veya ortam değişkeninden okunur.
İşlemler
İşlem (Transaction) ve ACID
- Havale: Ece'nin hesabına 300 TL ekle ve Ali'nin hesabından 300 TL düş. İki
UPDATE'ten biri olur diğeri olmazsa para yoktan var olur ya da kaybolur. - İşlem (transaction): tek bir iş birimi olarak yürütülen bir veya daha fazla SQL komutu: ya hepsi ya hiçbiri.
- JDBC'de varsayılan auto-commit açıktır: her komut hemen kalıcı olur.
conn.setAutoCommit(false)→ komutlar →conn.commit()(kalıcı yap) veyaconn.rollback()(geri al).
Bölünmezlik: işlemin ya tamamı ya hiçbiri uygulanır.
Tutarlılık: işlem sonunda tüm kısıtlar (ör. bakiye ≥ 0) sağlanır.
Yalıtım: eşzamanlı işlemler birbirinin yarım hâlini görmez.
Kalıcılık: commit edilen veri, elektrik kesilse de kaybolmaz.
İşlemler
Havale Örneği: Kurulum ve Sonuç
static final String YATIR = "UPDATE hesaplar SET bakiye = bakiye + ? WHERE id = ?"; static final String CEK = "UPDATE hesaplar SET bakiye = bakiye - ? WHERE id = ?"; public static void main(String[] args) throws SQLException { String url = "jdbc:sqlite::memory:"; // bellekte, geçici try (Connection conn = DriverManager.getConnection(url); Statement st = conn.createStatement()) { st.execute("CREATE TABLE hesaplar (id INTEGER PRIMARY KEY, " + "sahip TEXT, bakiye INTEGER CHECK (bakiye >= 0))"); st.execute("INSERT INTO hesaplar(sahip, bakiye) " + "VALUES ('Ali', 1000), ('Ece', 500)"); havale(conn, 1, 2, 300); // Ali → Ece 300 TL havale(conn, 1, 2, 5000); // Ali'nin parası yetmez yazdir(conn); } }
300 TL aktarıldı. Geri alındı: 5000 TL Ali: 700 Ece: 800
CHECK (bakiye >= 0): bakiyeyi eksiye düşüren komutSQLExceptionfırlatır.- İkinci havalede Ece'ye 5000 TL yatırılmıştı;
rollbackbunu da geri aldı. havalemetodu sonraki slayttadır;yazdir,listelegibi birSELECTdöngüsüdür.
İşlemler
commit ve rollback: Adım Adım
Auto-commit kapatılır: bundan sonraki değişiklikler commit'e kadar geçicidir.
Ece'ye 300 TL yatırılır: 500 → 800.
Ali'den 300 TL çekilir: 1000 → 700. Kısıt sağlanıyor.
commit(): iki değişiklik birlikte kalıcı olur.
finally: auto-commit yeniden açılır; metot biter.
İkinci çağrı: Ece'ye 5000 TL yatırılır (geçici): 800 → 5800.
700 − 5000 < 0 olurdu: CHECK bozulur, SQLException fırlar.
rollback(): geçici yatırma da geri alınır. Para ne kayboldu ne çoğaldı.
static void havale(Connection conn, int kimden, int kime, int tutar) throws SQLException { conn.setAutoCommit(false); // işlem başlar try (PreparedStatement p1 = conn.prepareStatement(YATIR); PreparedStatement p2 = conn.prepareStatement(CEK)) { p1.setInt(1, tutar); p1.setInt(2, kime); p1.executeUpdate(); // alıcıya yatır p2.setInt(1, tutar); p2.setInt(2, kimden); p2.executeUpdate(); // göndericiden çek conn.commit(); // kalıcı yap System.out.println(tutar + " TL aktarıldı."); } catch (SQLException e) { conn.rollback(); // geri al System.out.println("Geri alındı: " + tutar + " TL"); } finally { conn.setAutoCommit(true); } }
Özet
Özet
| Konu | Ana fikir |
|---|---|
| Veritabanı | Kalıcı, düzenli, sorgulanabilir veri; VTYS yönetir. Tablo, satır, sütun, birincil anahtar. |
| SQLite | Sunucusuz, gömülü, tek dosya. Adres: jdbc:sqlite:sample.db; sürücü jar'ı classpath'te olmalı. |
| SQL | CREATE TABLE, INSERT, SELECT, UPDATE, DELETE; WHERE, ORDER BY, LIMIT. |
| JDBC | DriverManager → Connection → Statement / PreparedStatement → ResultSet. |
| Çalıştırma | execute (tablo), executeUpdate → int, executeQuery → ResultSet; while (rs.next()). |
| Güvenlik | Kullanıcı girdisi her zaman ? ve setXxx ile; SQL metnine eklenmez. |
| İşlem | setAutoCommit(false), commit(), rollback(): ya hepsi ya hiçbiri (ACID). |
| Kaynaklar | try-with-resources: rs, stmt, conn ters sırada kapanır; SQLException kontrol edilen istisnadır. |
Özet
Sık Yapılan Hatalar
No suitable driver found for jdbc:sqlite:sample.dbunreported exception SQLException; must be caught or declared to be thrownno such table: usersVALUES(Ahmet, …):no such column: AhmetVALUES('Ali'nin'):near "nin": syntax errorexecuteQuery ile INSERT:query does not return ResultSetrs.getString(0); sıra 1'den başlar:column 0 out of bounds [1,3]Özet
Örnek Problemler 1
Problem 1: SELECT hangi satırları döndürür?
CREATE TABLE users (id INTEGER PRIMARY KEY, name TEXT); INSERT INTO users(name) VALUES ('Ali'); INSERT INTO users(name) VALUES ('Can'); DELETE FROM users WHERE id = 2; INSERT INTO users(name) VALUES ('Ece'); UPDATE users SET name = 'Efe' WHERE id = 1; SELECT * FROM users;
Problem 2
Kişi programı (kisiler.db ile) ikinci kez çalıştırılıyor. Çıktının ilk bloğu (ilk ---'e kadar) ve son bloğu nedir?
Cevapları göster
(1, Efe)ve(2, Ece). Can silinince en büyük id 1 kaldı; Ece en büyük id + 1 = 2 aldı (id yeniden kullanıldı).UPDATEyalnızca 1 numaralı satırı değiştirdi.- Dosya kalıcıdır; ilk çalıştırmadan Ayşe (id 2) kalmıştı ve
IF NOT EXISTStabloyu silmez. Yeni kayıtlar id 3 (Ahmet) ve 4 (Ayşe) alır. İlk blok:2 Ayşe Demir 40,3 Ahmet Akdeniz 35,4 Ayşe Demir 40. Son blok:2 Ayşe Demir 40,4 Ayşe Demir 40(aynı kişi iki kez kayıtlı).
Özet
Örnek Problemler 2
Problem 3: Giriş kontrolü
String sql = "SELECT * FROM kisiler WHERE ad = '" + ad
+ "' AND sifre = '" + sifre + "'";
ResultSet rs = stmt.executeQuery(sql);
boolean girisBasarili = rs.next();Tabloda 3 kişi var. Kullanıcı ad olarak ahmet, şifre olarak ' OR '1'='1 yazarsa oluşan SQL nedir, kaç satır döner, giriş başarılı olur mu?
Problem 4
havale metodundan setAutoCommit(false), commit() ve rollback() satırları çıkarılsaydı (her komut kendi başına kalıcı) program sonunda Ali ve Ece'nin bakiyesi ne olurdu?
Cevapları göster
SELECT * FROM kisiler WHERE ad = 'ahmet' AND sifre = '' OR '1'='1'.AND,OR'dan önce uygulanır:(… AND …) OR '1'='1'her satırda doğru → 3 satır,rs.next()true: şifresiz giriş! Çözüm:WHERE ad = ? AND sifre = ?ilePreparedStatement→ 0 satır.- Ali: 700, Ece: 5800. İkinci havalede yatırma hemen kalıcı oldu, çekme
CHECKyüzünden başarısız oldu ve geri alacak işlem yoktu: 5000 TL yoktan var oldu (program yine de “Geri alındı” yazar).
Özet
Alıştırmalar
- Silme programını değiştirin:
executeUpdate0 döndürürseKayıt bulunamadı.yazsın. ogrenciler(id, ad, vize, final)tablosunu oluşturun; Ada (60, 70), Bora (30, 50), Cem (80, 40) öğrencileriniPreparedStatementile bir döngüde ekleyin. Ortalaması (vize %40, final %60) 50 ve üzeri olanları büyükten küçüğe listeleyin.- Menülü bir program yazın: 1-Ekle, 2-Güncelle, 3-Sil, 4-Listele.
Scannerveswitchkullanın; güncellenecek/silinecek id yoksaKullanıcı bulunamadı.yazsın. - Bir oyunun skorlarını
skorlar(oyuncu, puan)tablosuna kaydedin ve en yüksek 10 skoru listeleyin.
Cevaplar / ipuçları
int sayi = stmt.executeUpdate(sql); if (sayi > 0) System.out.println("Veri silindi!"); else System.out.println("Kayıt bulunamadı.");SELECT ad, vize * 0.4 + final * 0.6 AS ort FROM ogrenciler WHERE vize * 0.4 + final * 0.6 >= 50 ORDER BY ort DESC· Çıktı:Ada 66.0,Cem 56.0(Bora 42.0 elenir).getDouble("ort")ile okunur.nextInt()'ten sonranextLine()ile satır sonunu temizleyin.UPDATE … WHERE id = ?veDELETE … WHERE id = ?içinexecuteUpdate'in döndürdüğü sayı 0 ise kullanıcı yoktur.SELECT oyuncu, puan FROM skorlar ORDER BY puan DESC LIMIT ?veps.setInt(1, 10). EklemedeINSERT INTO skorlar(oyuncu, puan) VALUES(?, ?).
Özet
Kaynaklar
- Oracle, The Java Tutorials: JDBC Database Access (Establishing a Connection; Processing SQL Statements with JDBC; Using Prepared Statements; Using Transactions).
- Oracle, Java SE 21 API Documentation:
java.sqlpaketi (DriverManager,Connection,PreparedStatement,ResultSet). - SQLite belgeleri, sqlite.org: SQL As Understood By SQLite; Datatypes In SQLite; Appropriate Uses For SQLite.
- Xerial, SQLite JDBC Driver, github.com/xerial/sqlite-jdbc.
- P. Deitel ve H. Deitel, Java: How to Program, 11. baskı, Pearson (Accessing Databases with JDBC).
- C. S. Horstmann, Core Java, Volume II: Advanced Features, 12. baskı, Pearson (Database Programming).
- OWASP, SQL Injection Prevention Cheat Sheet.