Ders İçeriği

Java Database Connectivity (JDBC), Java uygulamalarının veritabanlarıyla etkileşim kurmasını sağlayan bir Java API'sidir. JDBC, farklı veritabanı sistemlerine (MySQL, PostgreSQL, Oracle, SQL Server vb.) tek tip bir arayüz üzerinden erişim imkanı sunar. Bu sayede, veritabanı değişse bile Java kodunda minimum değişiklik yapmak yeterli olur.

JDBC Mimarisi

JDBC mimarisi genellikle dört ana bileşenden oluşur:

  1. Java Uygulaması: Veritabanı işlemlerini gerçekleştiren Java kodunuz.
  2. JDBC API: Java uygulamalarının veritabanı ile iletişim kurmak için kullandığı arayüzler ve sınıflar kümesi (java.sql paketi).
  3. JDBC Sürücü Yöneticisi (Driver Manager): Uygulama ile veritabanı sürücüleri arasında köprü görevi görür. Doğru sürücüyü bulur ve veritabanı bağlantısını kurar.
  4. JDBC Sürücüsü (Driver): Belirli bir veritabanı türü için JDBC API çağrılarını veritabanının anlayacağı protokollere çeviren yazılımdır. Her veritabanı için ayrı bir JDBC sürücüsü gerekir.

JDBC Adımları

Bir Java uygulamasında JDBC kullanarak veritabanı işlemleri yapmak için genellikle şu adımlar izlenir:

  1. JDBC Sürücüsünü Yükleme/Kaydetme: Veritabanı sürücüsünü JVM'ye yüklemek gerekir. Java 6 ve sonraki sürümlerde, Class.forName() metodunu kullanmaya gerek kalmadan sürücü otomatik olarak yüklenir. Ancak eski sürümlerle uyumluluk veya belirli durumlarda hala kullanılabilir.
  2. Veritabanı Bağlantısı Kurma: DriverManager.getConnection() metodu kullanılarak veritabanına bir bağlantı (Connection nesnesi) kurulur. Bu metot, veritabanı URL'si, kullanıcı adı ve şifre gibi bilgileri alır.
  3. SQL Sorgusu Oluşturma: SQL sorgularını veritabanına göndermek için StatementPreparedStatement veya CallableStatement nesneleri oluşturulur.
    • Statement: Basit, parametresiz SQL sorguları için kullanılır.
    • PreparedStatement: Parametreli SQL sorguları için daha güvenli ve performanslıdır. SQL enjeksiyon saldırılarını önler.
    • CallableStatement: Saklı prosedürleri (stored procedures) çağırmak için kullanılır.
  4. SQL Sorgusunu Çalıştırma: Oluşturulan sorgu nesnesi üzerinden executeQuery() (SELECT için), executeUpdate() (INSERT, UPDATE, DELETE için) veya execute() metotları çağrılır.
  5. Sonuçları İşleme: executeQuery() metodu bir ResultSet nesnesi döndürür. Bu nesne, sorgu sonuçlarını satır satır gezmek ve verilere erişmek için kullanılır.
  6. Bağlantıyı Kapatma: Kaynak sızıntılarını önlemek için ConnectionStatement ve ResultSet nesneleri close() metodu çağrılarak kapatılmalıdır. try-with-resources yapısı bu işlemi otomatikleştirir.

Örnek: MySQL Veritabanı Bağlantısı

Bu örnekte, bir MySQL veritabanına bağlanıp basit bir SELECT sorgusu çalıştıracağız. Bu örneği çalıştırmadan önce:

  • Sisteminizde bir MySQL sunucusu kurulu olmalı.
  • Bir veritabanı (örneğin testdb) ve bir tablo (örneğin ogrenciler) oluşturulmuş olmalı.
  • MySQL JDBC sürücüsü (Connector/J) projenizin classpath'ine eklenmiş olmalı (Maven/Gradle kullanıyorsanız bağımlılık olarak ekleyin, manuel ise JAR dosyasını projenize ekleyin).

ogrenciler tablosu örneği:

CREATE DATABASE testdb;
USE testdb;
CREATE TABLE ogrenciler (
    id INT PRIMARY KEY AUTO_INCREMENT,
    ad VARCHAR(50),
    soyad VARCHAR(50),
    yas INT
);
INSERT INTO ogrenciler (ad, soyad, yas) VALUES ('Ahmet', 'Yılmaz', 20);
INSERT INTO ogrenciler (ad, soyad, yas) VALUES ('Ayşe', 'Demir', 22);

Java Kodu:

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;

public class JDBCExample {
    // Veritabanı bağlantı bilgileri
    private static final String DB_URL = "jdbc:mysql://localhost:3306/testdb";
    private static final String USER = "root";
    private static final String PASS = "your_password"; // Kendi şifrenizi girin

    public static void main(String[] args) {
        // Try-with-resources ile kaynakları otomatik kapatma
        try (Connection conn = DriverManager.getConnection(DB_URL, USER, PASS);
             PreparedStatement pstmt = conn.prepareStatement("SELECT id, ad, soyad, yas FROM ogrenciler WHERE yas > ?")) {

            System.out.println("Veritabanına başarıyla bağlandı!");

            // Parametre set etme
            pstmt.setInt(1, 21); // Yaşı 21'den büyük olanları seç

            // Sorguyu çalıştırma ve sonuçları işleme
            ResultSet rs = pstmt.executeQuery();

            System.out.println("\nYaşı 21'den büyük öğrenciler:");
            while (rs.next()) {
                // Her satırdaki sütun değerlerini alma
                int id = rs.getInt("id");
                String ad = rs.getString("ad");
                String soyad = rs.getString("soyad");
                int yas = rs.getInt("yas");

                // Konsola yazdırma
                System.out.printf("ID: %d, Ad: %s, Soyad: %s, Yaş: %d\n", id, ad, soyad, yas);
            }

            // Yeni öğrenci ekleme
            PreparedStatement insertPstmt = conn.prepareStatement("INSERT INTO ogrenciler (ad, soyad, yas) VALUES (?, ?, ?)");
            insertPstmt.setString(1, "Cem");
            insertPstmt.setString(2, "Can");
            insertPstmt.setInt(3, 25);
            int affectedRows = insertPstmt.executeUpdate();
            System.out.println("\n" + affectedRows + " satır eklendi.");

            // Öğrenci güncelleme
            PreparedStatement updatePstmt = conn.prepareStatement("UPDATE ogrenciler SET yas = ? WHERE ad = ?");
            updatePstmt.setInt(1, 21);
            updatePstmt.setString(2, "Ahmet");
            affectedRows = updatePstmt.executeUpdate();
            System.out.println(affectedRows + " satır güncellendi.");

            // Öğrenci silme
            PreparedStatement deletePstmt = conn.prepareStatement("DELETE FROM ogrenciler WHERE ad = ?");
            deletePstmt.setString(1, "Cem");
            affectedRows = deletePstmt.executeUpdate();
            System.out.println(affectedRows + " satır silindi.");

        } catch (SQLException e) {
            System.err.println("Veritabanı hatası oluştu: " + e.getMessage());
            e.printStackTrace();
        } catch (Exception e) {
            System.err.println("Genel bir hata oluştu: " + e.getMessage());
            e.printStackTrace();
        }
    }
}

Bağlantı Havuzları (Connection Pools)

Gerçek dünya uygulamalarında, her veritabanı işlemi için yeni bir bağlantı açıp kapatmak performans açısından verimsizdir. Bu nedenle, bağlantı havuzları (connection pools) kullanılır. Bağlantı havuzu, önceden oluşturulmuş ve kullanıma hazır veritabanı bağlantılarının bir koleksiyonudur. Uygulama bir bağlantıya ihtiyaç duyduğunda, havuzdan mevcut bir bağlantıyı alır ve işi bittiğinde havuza geri bırakır. Bu, bağlantı açma/kapatma maliyetini ortadan kaldırır ve performansı artırır. HikariCP, c3p0, Apache DBCP gibi popüler bağlantı havuzu kütüphaneleri bulunmaktadır.

JDBC, Java uygulamalarının veritabanlarıyla etkileşim kurması için temel ve güçlü bir mekanizmadır. Modern uygulamalarda genellikle ORM (Object-Relational Mapping) araçları (Hibernate, JPA) veya Spring JDBC gibi daha yüksek seviyeli soyutlamalar kullanılsa da, JDBC'nin temelini anlamak önemlidir. Bir sonraki derste Ağ Programlama konusunu inceleyeceğiz.