Java ve Spring Mülakat Soruları

Yazılım geliştirme mülakatları için hazırlanmış sorular ve cevaplar

Java Temel

Java Class Loader nedir?

Java'da ClassLoader, Java programlarındaki sınıf dosyalarını yüklemek için kullanılan bir sınıftır. Java kodu, javac derleyicisi tarafından sınıf dosyasına derlenir ve JVM, sınıf dosyasında yazılmış byte kodlarını çalıştırarak Java programını yürütür.

Java'da üç varsayılan ClassLoader vardır: Bootstrap, Extension ve System (Application) ClassLoader.

  1. Bootstrap ClassLoader: rt.jar ve diğer temel sınıflar gibi standart JDK sınıf dosyalarını yükler. Tüm ClassLoader'ların atasıdır ve herhangi bir atası yoktur. Primordial ClassLoader olarak da adlandırılır.
  2. Extension ClassLoader: Bu sınıf yükleyicisi, kullanıcının genişletilmiş sınıf dosyalarını yüklemesine izin verir. Bu sınıflar, "java.ext.dirs" olarak tanımlanan özel bir klasörde bulunur.
  3. System / Application ClassLoader: Bu sınıf yükleyicisi, kullanıcının kendi sınıf dosyalarını yüklemesine izin verir. (Yazılan Kodlar) Bu sınıflar, "java.class.path" olarak tanımlanan özel bir klasörde bulunur.

Java'da String ve StringBuilder arasındaki fark?

String: String sınıfı değiştirilemez (immutable) bir sınıftır. Bir String nesnesi oluşturulduktan sonra, onun içeriği değiştirilemez. Örneğin, bir String üzerinde herhangi bir değişiklik yapmak (bir karakter eklemek, çıkarmak veya değiştirmek) yeni bir String nesnesi oluşturur.

StringBuilder: StringBuilder sınıfı değiştirilebilir (mutable) bir sınıftır. Bir StringBuilder nesnesi oluşturulduktan sonra, onun içeriği değiştirilebilir. Bu, aynı nesne üzerinde değişiklik yapmanıza olanak tanır ve genellikle daha verimlidir.

Java'da StringBuilder ve StringBuffer arasındaki fark?

StringBuilder: Thread-safe değildir. Bu, StringBuilder nesnesinin aynı anda birden fazla thread tarafından güvenli bir şekilde kullanılamayacağı anlamına gelir. Tek thread'li uygulamalarda veya birden fazla thread'in aynı StringBuilder nesnesine erişmeyeceği durumlarda kullanılması uygundur.

StringBuffer: Thread-safe'dir. Bu sınıfın tüm yöntemleri senkronize edilmiştir, yani aynı anda birden fazla thread tarafından güvenli bir şekilde kullanılabilir. Bu nedenle, çok thread'li uygulamalarda veya birden fazla thread'in aynı StringBuffer nesnesine erişmesi gereken durumlarda kullanılması uygundur.

Javada Access modifiers nelerdir?

  1. Default: Aynı sınıftan, altsınıftan ve aynı package'den erişilebilir. Javada bir access modifier tanımlanmazsa default olarak kabul edilir ve bu geçerli olur.
  2. Private: Sadece aynı sınıftan erişilebilir.
  3. Protected: Aynı sınıftan, aynı packageden ve alt sınıflardan erişilebilir.
  4. Public: Her yerden erişilebilir.

ArrayList ile Array arasındaki fark nedir?

  1. Boyut: Array'ler, boyutları sabit olan veri yapılarıdır, yani tanımlandıkları boyutta kalırlar. ArrayList'ler ise boyutları dinamik olarak değiştirilebilen veri yapılarıdır, yani öğe sayısı arttıkça boyutları da otomatik olarak artar.
  2. Tür: Array'ler, tek bir türdeki verileri depolamak için kullanılır. ArrayList'ler ise farklı türlerdeki verileri depolamak için kullanılabilir.
  3. İşlevsellik: Array'ler, basit bir veri yapısıdır ve sınırlı işlevselliğe sahiptirler. ArrayList'ler ise daha gelişmiş işlevselliklere sahiptir. Örneğin, ArrayList'lerde verileri ekleme, silme, sıralama gibi işlemler kolayca yapılabilir.
  4. İşlem hızı: Array'ler, verileri doğrudan belleklerinde tuttuklarından hızlı işleme imkanı sağlarlar. ArrayList'ler ise verileri heap bellekte tuttuklarından işlem hızı, Array'lere göre daha yavaş olabilir.
  5. Tip güvenliği: Array'ler, tür güvenliğine sahiptir. Yani, tanımlanan tür haricinde veri eklenemez. ArrayList'ler ise tür güvenliği sağlamak için cinsiyetli yapılar ile çalışırlar.
  6. Null değerler: Array'ler null değerler içerebilirken, ArrayList'ler null değerleri kabul etmezler.

List, Set, Hashmap acıklayınız?

Set Nesnesi: Kendisine verilen elemanların her birinde sadece bir tanesini tutar. Kopya ya da tekrarlanan elemanları barındırmaz.

List Nesnesi: Kendisine verilen elemanları sıralı şekilde tutar. Tekrarlana elemanları barındırabilir.

Map Nesnesi: Her biri birbirinden farklı anahtarlar ile eşleştirilen nesnelerden oluşur.

Javada Statement ve PreparedStatement arasındaki farklar?

PreparedStatement ile SQL ifadelerimizi veritabanımızda önceden derlenmek üzere gönderebileceğimiz ve her defasında derlenmiş hale değer göndererek tekrar tekrar kullanabileceğimiz bir yapıdır.

Statement nesnesinde programımız üzerinde ifade derlenip veritabanımız sadece sorgulama işlemini gerçekleştirmekte idi.

Statement

  • SQL sorgusunun yalnızca bir kez yürütülmesi gerektiğinde kullanılır.
  • Çalışma zamanında parametreleri iletemezsiniz.
  • Performans çok düşük.
  • Normal SQL sorgularını yürütmek için kullanılır.
  • Binary verileri okumak ve yazmak için kullanılmaz.

PreparedStatement

  • SQL sorgusunun birden çok kez yürütülmesi gerektiğinde kullanılır
  • Çalışma zamanında parametreleri iletebilirsiniz.
  • Birden çok kez çalıştırılacak sorgular için kullanılır.
  • Performans Statement'ten daha iyidir.
  • Dinamik SQL sorgularını çalıştırmak için kullanılır.
  • Binary verileri okumak ve yazmak için Readydstatement'ı kullanabiliriz.
  • PreparedStatement, özel karakterlerden otomatik olarak kaçtığı için SQL enjeksiyon saldırılarını önlememize yardımcı olur.

ArrayList ile LinkedList arasındaki fark nedir?

  1. Dizilerde ulaşmak istediğimiz elemana indisini girerek ulaşırız. Linked List'lerde ise ulaşmak istediğimiz elemanlara point eden pointerlar vasıtasıyla ulaşırız.
  2. Dizilerde eleman ekleme, silme gibi işlemler Linked List'lere göre performans açısından daha maliyetlidir. Örneğin; 1000 elemanlı bir dizimiz tanımlı olsun. Bu dizinin 500.cü elemanını silmek istediğimizde, bu elemandan sonra gelen her eleman bir sıra geri kaydırılacak bu da performans kaybına yol açacaktır. Linked List'te ise bu işlem sadece basit pointer operasyonlarıyla gerçekleştirilir ve kaydırma işlemlerine gerek kalmaz. Bu sayede performanstan kazanç sağlanmaktadır.
  3. Linked List dinamiktir. Dizi tanımlaması yapılırken en başında veri boyutunu belirtmemiz gerekirken, Linked List'lerde ihtiyaç duyduğumuzda boyutu artırabilir, silme işlemlerimizden sonra Linked List boyutumuzu küçültebiliriz.

Final anahtar kelimesi ne işe yarar?

  • Final değişkenler: Değiştirilemez. Static ile beraber Constant olarak kullanılabilir.
  • Final class: Extend edilemez
  • Final methods: Override edilemez.

Error ve Exception arasındaki farklar?

Error, jvm tarafından runtime'da handle edilmesi mümkün olmayan türden hatalardır. Exception ise try catch ile handle edilebilir. Java'da exceptionları 5 farklı keyword ile handle edilebilir. -- Try -- Catch -- Finally -- Throw -- Throws

Checked Exception ve Unchecked Exception arasındaki farklar?

RuntimeException ve Error dışında Throwable sınıfını extend eden sınıflar Checked Exceptions olarak tanımlanabilir. Checked Exceptionlar compile edilirken alınan hatalardır. (IOException, SQLException)

RuntimeException sınıfını extend eden exceptionlar Unchecked Exceptionlar olarak adlandırılır. Compile edilirken kontrol edilip gözükmez, (ArithmeticException, NullPointerException)

Java Thread ile VirtuaL Thread arasndaki fark nedir?

Java'da kullandığımız geleneksel threadler (bundan sonra Platform Thread olarak da bahsedeceğiz) işletim sistemi tarafından yönetilir ve planlanır. Yeni bir platform thread oluşturmak için bir sistem çağrısı yapılmalıdır ve bu maliyetli bir işlemdir.

Geleneksel threadlerin aksine virtual threadler JVM tarafından yönetilir. Bu nedenle, tahsisleri bir sistem çağrısı gerektirmez ve işletim sisteminin bağlam anahtarından (context switch) muaftırlar. Sonuç olarak, sistemin bağlam anahtarından kurtulduğumuz için daha az maliyetle birçok virtual thread üretebiliriz. Ayrıca virtual threadler, gerçek çekirdek thread olan taşıyıcı threadler üzerinde çalışır. Virtual threadler, Java kodu perspektifinden normal threadler gibi hissedilir, ancak işletim sistemi threadlerine 1:1 eşlenmezler. Taşıyıcı thread havuzundan uygun olan taşıyıcı threadin üzerine virtual threadler eşlenir.

Java Multi Thread nedir?

Thread safe, birden çok threadin bir kaynağı aynı anda kullanması durumlarında ortaya çıkan tutarsızlıkların sonucundaki hatalara karşı; o anki threadin kaynağını güvenceye alan ve bunu o kaynağı kullanan tüm threadler için uygulayan bir konsepttir.

Asenkron yani multithreading bir yapıda threadlerin aynı veri kaynağına erişip değiştirmeye çalışması, hatalı davranışların sergilenmesine ve tutarlı bir sonuç elde edilememesine neden olabilir. Bu ve bunun gibi problemleri önlemek için threadleri güvenli bir şekilde tasarlamak ve geliştirmek gerekir. Bu metodolojiye thread safe, iş parçacığı güvenliği denir.

Serilization nedir?

Bir nesnenin veya bir sınıfın saklanacak forma dönüştürülme işlemidir. Extend edilen Serilization sınıfı alt sınıf olan kullanacağımız sınıfın byte'lar halinde streamlere yazılabilir böylece bir java objesi veritabanına kaydedilebilir.

Deserilization ise byte haline çevrilen java objesinin eski haline çevrimine denir.

Java Thread safe?

Thread safe, birden çok threadin bir kaynağı aynı anda kullanması durumlarında ortaya çıkan tutarsızlıkların sonucundaki hatalara karşı; o anki threadin kaynağını güvenceye alan ve bunu o kaynağı kullanan tüm threadler için uygulayan bir konsepttir.

Asenkron yani multithreading bir yapıda threadlerin aynı veri kaynağına erişip değiştirmeye çalışması, hatalı davranışların sergilenmesine ve tutarlı bir sonuç elde edilememesine neden olabilir. Bu ve bunun gibi problemleri önlemek için threadleri güvenli bir şekilde tasarlamak ve geliştirmek gerekir. Bu metodolojiye thread safe, iş parçacığı güvenliği denir.

Java ConcurrentHashMap?

ConcurrentHashMap, Java'da eşzamanlı (concurrent) programlama için kullanılan bir veri yapısıdır. Birden fazla thread tarafından aynı anda güvenli bir şekilde erişilebilen bir harita (map) implementasyonudur.

ConcurrentHashMap, segmentasyon (segmentation) adı verilen bir teknik kullanır. Bu teknik, haritayı birden fazla segmente böler ve her segment kendi kilidine sahiptir. Bu sayede, farklı segmentlere erişen threadler birbirini engellemez ve performans artar.

ConcurrentHashMap, Hashtable'a göre daha iyi performans sunar çünkü Hashtable tüm haritayı kilitlerken, ConcurrentHashMap sadece ilgili segmenti kilitler. Bu da birden fazla threadin aynı anda farklı segmentlere erişmesine izin verir.

Solid prensipleri nelerdir?

  1. Single responsibilty: Bir nesne ya da bir sınıfın tek bir sorumluluğu olmalıdır.
  2. Open-closed: Bir sınıf değişime kapalı gelişmeye açık olmalıdır.
  3. Liskov's Substitution: Nesneler programın çalışmasında sorun yaratmadan kendi alt örnekleriyle değiştirilebilmelidir.
  4. Interface Segregation: Nesneler ihtiyaç duymadıkları metotların interfacelerinden ayrıştırılmalıdır.
  5. Dependency Inversion: Yüksek seviyeli sınıflar düşük seviyeli sınıflara bağlı olmamalı, her ikisi de soyut kavramlara bağlı olmalıdır.

Single Responsibilty nedir?

Single responsibilty bir nesnenin tek bir amaçla yaratılmasını konu alır. Bağlı olduğu sınıfın içerdiği davranışsal özellikler tek bir amaca uygun olmalı başka bir davranış göstermemelidir. Örneğin bir çalışan sınıfı içerisinde vergi hesaplama fonskiyonu bulunamaz. Bu single responsibilty prensibine aykırı bir kod yazım şeklidir.

Dependency Injection nedir?

"Dependency Inversion" prensibinin uygulanmasını içeren bir patterndir.Dependency Injection tekniğinde bağımlılık oluşturacak parçalarının ayrılıp, bunların sisteme dışarıdan verilmesi (enjekte edilmesi) ile meydana gelir. Temel olarak 3 tür DI vardır. Bunlar;

  • Constructor Injection,
  • Setter Injection,
  • Method Injection

Tüm yöntemler bağımlı olan sınıfları dışarıdan enjekte etmeye dayanır.

DAO nedir?

DAO Data Access Object ifadesini: Bu araç geliştiricilere özellikle Java kaynaklı veri erişim araçları ile daha kolay çalışma imkanı sunar. Bir yazılım uygulamasında veritabanı veya diğer veri kaynaklarına erişimi sağlayan bir tasarım desenidir. DAO ile diğer katmanlar etkilenmeden veritabanı ve bilgi bankası değiştirilebilir.

Spring Framework

Spring Boot ve Spring Framework arasındaki fark nedir?

- Spring Framework → Konfigürasyon ağırlıklı, XML veya Java Config gerekebilir.

- Spring Boot → Spring üzerine kuruludur, hazır starter bağımlılıkları ve otomatik konfigürasyonu sayesinde çok daha hızlı geliştirme sağlar.

Özet: Spring Boot = Spring + Auto Configuration + Embedded Server + Production tools

Spring Boot Auto-Configuration nasıl çalışır?

Spring Boot uygulama başlarken classpath'teki bağımlılıkları kontrol eder ve uygun konfigürasyonu otomatik yükler.

  • spring-boot-starter-web varsa → DispatcherServlet, Tomcat otomatik başlatılır.
  • spring-boot-starter-data-jpa varsa → EntityManagerFactory, DataSource otomatik oluşturulur.

Bunu sağlayan mekanizma: @EnableAutoConfiguration anotasyonu.

Spring Boot Actuator nedir?

Spring Boot Actuator, uygulamanın çalışma zamanında sağlık durumu, metrikler, loglar, env bilgileri gibi üretim seviyesinde izleme (monitoring) ve yönetim özellikleri sağlar.

  • /actuator/health → Uygulamanın sağlık durumu
  • /actuator/metrics → Bellek, CPU, istek sayısı
  • /actuator/env → Ortam değişkenleri

Spring Boot'ta application.properties ve application.yml farkı nedir?

- application.properties → Anahtar-değer (key=value) formatındadır.

- application.yml → YAML formatında, daha okunabilir ve hiyerarşik yapı destekler.

Spring Boot'ta Profil (Profile) nedir?

Spring Boot, farklı ortamlar için (dev, test, prod) ayrı konfigürasyonlara izin verir. @Profile anotasyonu ile hangi bean'in hangi ortamda çalışacağını belirleyebiliriz.

@Profile("dev")
@Bean
public DataSource devDataSource() {
    ...
}

Spring Boot Security ile kimlik doğrulama nasıl yapılır?

Spring Security, Spring Boot'ta otomatik entegre gelir. Varsayılan olarak tüm endpointler korunur, user isimli kullanıcı oluşturulur ve şifre konsolda gösterilir. Gelişmiş senaryolar için:

  • JWT tabanlı kimlik doğrulama
  • OAuth2 / OpenID Connect entegrasyonu
  • Role-based access control

Spring'de @Transactional anotasyonu kullanılmasına rağmen neden rollback olmuyor?

  1. Exception türü rollback tetiklemiyor olabilir
    Spring, varsayılan olarak sadece RuntimeException ve Error tiplerinde rollback yapar. Checked Exception (örn. IOException, SQLException) fırlatılırsa rollback olmaz.
    @Transactional(rollbackFor = Exception.class)
    public void myMethod() throws Exception {
        ...
    }
  2. Metodun aynı sınıf içinde çağrılması (self-invocation)
    Spring @Transactional, AOP proxy üzerinden çalışır. Eğer bir sınıf içinde transactional metod, yine aynı sınıftaki başka bir metod tarafından çağrılıyorsa proxy devreye girmez → rollback çalışmaz.

    Çözüm: Transactional metodu başka bir bean'den çağır veya aspectJ ile compile-time weaving kullan.

  3. Transactional metod public değilse
    Spring AOP proxy, sadece public metodlara transactional uygular. Eğer metod private, protected veya default ise rollback çalışmaz.

    Çözüm: Transactional metod public olmalı.

  4. Exception yakalanıp swallow (yutuluyorsa)
    Eğer exception try-catch içinde yakalanıp üst kata fırlatılmıyorsa rollback tetiklenmez.
    @Transactional
    public void saveData() {
        try {
            // hata fırlatılır
        } catch (Exception e) {
            // log atıp swallow ederse rollback OLMAZ
        }
    }

    Çözüm:

    • Exception tekrar fırlatılmalı (throw e;)
    • Ya da rollback manuel çağrılmalı: TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
  5. Transactional propagation yanlış ayarlanmış olabilir
    Örneğin REQUIRES_NEW kullanılırken iç transaction rollback olsa bile dış transaction rollback olmayabilir.

    Çözüm: Doğru propagation stratejisini seçmek (REQUIRED, REQUIRES_NEW, NESTED vs.).

  6. No proxy / yanlış yapılandırma
    • @EnableTransactionManagement unutulmuş olabilir.
    • Transaction manager (DataSourceTransactionManager, JpaTransactionManager) yanlış veya hiç tanımlanmamış olabilir.
  7. Read-only transaction
    Eğer @Transactional(readOnly = true) kullanıyorsan, bazı veritabanı sürücüleri update/delete işlemlerini commit etmeyebilir, rollback davranışı da farklı olabilir.

Özet:

@Transactional var ama rollback olmuyorsa en büyük sebepler:

  • Exception tipi (checked/unchecked farkı)
  • Self-invocation (aynı sınıf içinden çağrı)
  • Metodun public olmaması
  • Exception'ın swallow edilmesi
  • Yanlış propagation
  • Transaction yönetiminin devreye girmemesi

Thread Dump nedir?

- Thread Dump, JVM üzerinde o anda çalışan tüm thread'lerin (iş parçacıklarının) durumunu gösteren bir rapordur.

- İçinde şunlar olur:

  • Hangi thread çalışıyor, hangi kod satırında
  • Thread'in state'i (RUNNABLE, WAITING, BLOCKED, TIMED_WAITING vs.)
  • Lock'lar, deadlock bilgisi
  • Stack trace

Kısaca: Thread Dump = JVM'in "röntgen filmi"

Thread Dump ne zaman kullanılır?

  • Uygulama donmuşsa (hang, deadlock)
  • Yüksek CPU kullanımı varsa
  • Thread sayısı artıyorsa (thread leak)
  • Performans analizi yapmak gerektiğinde

Spring'te @Component, @Service, @Repository arasındaki farklar?

1. @Component
→ En genel stereotype anotasyondur.
→ Spring bean'i tanımlamak için kullanılır.
→ @Component ile işaretlenmiş sınıf, component-scan sırasında Spring IoC Container'a eklenir.

Ne zaman kullanılır?
→ Eğer sınıfın rolü service, repository veya controller gibi belirgin değilse, genel amaçlı bir Spring bileşeni olduğunu belirtmek için.

2. @Service
→ @Component'in specialization (özelleştirilmiş) halidir.
→ Semantik olarak bu sınıfın iş mantığını (business logic) içerdiğini belirtir.
→ Ekstra olarak Spring AOP ile iş katmanına yönelik işlemlerde (örneğin transaction, logging, security) anlam kazanır.

Ne zaman kullanılır?
→ Service/Business katmanı sınıflarında.

3. @Repository
→ @Component'in başka bir specialization'ıdır.
→ Semantik olarak bu sınıfın data access layer (DAO) olduğunu belirtir.
→ Ekstra özellik: Spring, @Repository ile işaretlenmiş sınıflarda veritabanı exception'larını Spring'in DataAccessException hiyerarşisine dönüştürür.

Ne zaman kullanılır?
→ Database erişim katmanında (JPA, JDBC, MongoDB, vb.).

Veritabanında 200 bin kayıt update ederken performans problemini nasıl çözersin?

  1. Tek sorgu ile toplu update yapmak ✅
    En hızlı yöntem, 200 bin satırı tek bir SQL UPDATE sorgusu ile güncellemektir.
    UPDATE orders
    SET status = 'CLOSED'
    WHERE status = 'PENDING';

    Avantajı: Tek transaction, tek IO, çok hızlı.
    Not: Eğer güncellemeler farklı değerler içeriyorsa, bu yöntem her zaman uygulanamayabilir.

  2. Batch Update (Toplu Güncelleme)
    Eğer her kayıt için farklı değer update edilecekse → tek tek update yerine batch kullanılır.
    jdbcTemplate.batchUpdate(
        "UPDATE employees SET salary = ? WHERE id = ?",
        employees,
        1000, // batch size
        (ps, emp) -> {
            ps.setBigDecimal(1, emp.getSalary());
            ps.setLong(2, emp.getId());
        }
    );

    Batch size genelde 1000 – 5000 arasında ayarlanır.
    Böylece 200.000 update = 200 query yerine, 200 batch × 1000 update olur → çok daha hızlı.

  3. Transaction Yönetimi
    Tek tek update + auto-commit açıksa → her kayıt için commit yapar, çok yavaş olur.
    Çözüm: Auto-commit'i kapatıp tek transaction veya batch transaction kullanmak.
    @Transactional
    public void bulkUpdate(...) {
       // batch işlemler
    }
  4. Index Optimizasyonu
    Update sırasında WHERE şartında kullanılan sütunlar indexlenmiş olmalı.
    UPDATE employees SET salary = salary * 1.1 WHERE department_id = 5;

    → department_id üzerinde index varsa çok daha hızlı çalışır.

  5. Partitioning veya Chunk Processing
    200 bin çok büyük değil ama milyonlarca kayıt olduğunda →
    - İşlemi chunk'lara bölmek gerekir (örneğin 10k kayıt = 20 işlem).
    - Spring Batch veya cursor ile yönetilebilir.

  6. Lock ve Concurrency Sorunları
    → Büyük update işlemi uzun sürerse, tabloyu kilitleyebilir.
    Çözüm:
    → Update işlemini off-peak saatlerde yapmak
    → Küçük batch'lerle güncellemek
    → Gerekiyorsa row-level lock ile yönetmek

  7. Veritabanı Özel Çözümleri
    → PostgreSQL: COPY ile geçici tabloya yükleyip join-update yapmak çok hızlıdır.
    → Oracle: MERGE INTO kullanılabilir.
    → MySQL: Bulk update için geçici tablo (LOAD DATA INFILE) ve join update yapılabilir.

Sepetteki veriyi nasıl tutarım nasıl hızlı getirirrim nasıl hızlı update ederim?

E-commerce gibi sistemlerde "sepet (shopping cart)" performansı kritik bir konudur.

1. Sepet verisini nerede tutarım?

Frontend tarafında (client-side):

  • localStorage veya sessionStorage → küçük sepetler için hızlı çözüm.
  • Redux / Context API → sayfa yenilendiğinde kaybolmaması için.

Avantaj: Hızlı, server yükünü azaltır.
Dezavantaj: User login olmadan farklı cihazlardan senkronize edemezsin.

Backend tarafında (server-side):

  • Database (RDBMS/MongoDB) → kalıcı depolama.
  • Cache (Redis, Memcached) → hızlı erişim için.

Genellikle Redis + DB birlikte kullanılır.
Redis → anlık sepet işlemleri (okuma/yazma çok hızlı).
DB → checkout sırasında kalıcı hale getirme.

2. Nasıl hızlı getiririm?

Cache (Redis) kullan:

Key → cart:userId
Value → JSON formatında sepet içeriği.
Böylece her istek DB'ye gitmez, Redis'ten milisaniyede gelir.

Indexleme yap:

DB'de userId + cartId üzerinde index olmalı.

API optimizasyonu:

GET /cart → tek endpoint, tüm ürünleri + toplam tutarı döner.
Gerekirse ürün bilgilerini batch query ile getir (N+1 probleminden kaçın).

3. Nasıl hızlı update ederim?

Redis Hash veya JSON set kullan:
Örn: HSET cart:123 productId:456 quantity 3
O(1) performans, çok hızlıdır.

Optimistic Locking (ETag, Versioning) kullan:
Aynı sepeti iki istek aynı anda güncellerse çakışmayı önler.

Partial update yap:
"Sepeti komple sil → tekrar yaz" yerine sadece değişen ürünü update et.

Event-driven yaklaşım:
Update geldiğinde bir Kafka/RabbitMQ event yayınla → DB & Redis senkronize olur.

4. Örnek Senaryo (Redis + DB birlikte)

→ Kullanıcı ürünü sepete ekler → API çağrısı alır.
→ API önce Redis'te günceller (cart:userId).
→ Checkout sırasında Redis'teki sepet alınır, DB'ye yazılır (kalıcı hale gelir).
→ Redis'te TTL (time to live) koy → mesela 7 gün işlem yapılmazsa otomatik silinsin.

5. Spring Boot Örneği (Redis ile)

@Service
public class CartService {

    private final RedisTemplate<String, Object> redisTemplate;
    private final String CART_KEY_PREFIX = "cart:";

    public CartService(RedisTemplate<String, Object> redisTemplate) {
        this.redisTemplate = redisTemplate;
    }

    public void addToCart(String userId, String productId, int quantity) {
        String key = CART_KEY_PREFIX + userId;
        redisTemplate.opsForHash().put(key, productId, quantity);
        redisTemplate.expire(key, Duration.ofDays(7)); // TTL
    }

    public Map<Object, Object> getCart(String userId) {
        String key = CART_KEY_PREFIX + userId;
        return redisTemplate.opsForHash().entries(key);
    }

    public void removeFromCart(String userId, String productId) {
        String key = CART_KEY_PREFIX + userId;
        redisTemplate.opsForHash().delete(key, productId);
    }
}

Özet

→ Küçük / basit projeler: localStorage + backend DB yeterli.
→ Orta / büyük ölçek: Redis + DB (hybrid model).
→ Çok büyük ölçek (Amazon, Trendyol, Hepsiburada): Redis Cluster + Kafka event + DB (CQRS ve Event Sourcing yaklaşımı).

Spring Boot'ta BatchConfig (Spring Batch) ile Cron Job kavramları hem benzer hem de farklı şeylerdir

1. Spring Batch (BatchConfig)

Ne iş yapar:
Büyük veri setleri üzerinde toplu işlem (read-process-write) yapar.
Örnek: 200.000 kaydı güncellemek, dosyadan veri okumak, ETL işlemleri.

Nasıl çalışır:
Job → Step → Reader, Processor, Writer
Chunk'lar ile parçalı işleme (batch update)
Restart, retry, skip, transaction yönetimi hazır gelir

Özellikleri:
Veri yoğun işleri yönetmek için optimize edilmiştir.
Database, CSV, Excel, JMS, Kafka gibi kaynaklardan veri okuyabilir.
Spring Batch framework'ü, iş mantığını ve state managementi sağlar.

2. Cron Job (@Scheduled)

Ne iş yapar:
Belirli zamanlarda veya periyodik olarak bir metodu çalıştırır.
Örnek: Her gece 00:00'da rapor oluşturmak, her 5 dakikada bir API çağrısı yapmak.

Nasıl çalışır:
Spring Boot'ta @EnableScheduling ve @Scheduled(cron = "...") ile yapılır.
Tek bir metod çağrılır, çoğunlukla küçük işleri yürütmek için uygundur.

Özellik Spring Batch (BatchConfig) Cron Job (@Scheduled)
Amaç Büyük veri işleme, ETL, toplu güncelleme Zamanlanmış görevler
Veri kaynağı DB, CSV, Excel, JMS, Kafka vs. Metod / iş mantığı
Transaction yönetimi Var (chunk, retry, skip) Yok / manuel
Performans Büyük veri setleri için optimize Küçük/orta işlerde yeterli
Zamanlama Spring Batch job launcher veya scheduler @Scheduled / cron
Durum yönetimi Job execution, Step execution, restart Yok

Yani:

Spring Batch = iş mantığı ve veri işleme
Cron Job = zamanlama ve tetikleme

Batch Büyük veri işleme yöntemınde hızlı mı çalışıyor ?

Evet, Spring Batch büyük veri işleme yönteminde hızlı çalışabilir, ama bu tamamen kullanım şekline ve yapılandırmaya bağlıdır.

1. Neden hızlı çalışabilir?

Chunk-based processing:
Büyük veri seti küçük parçalara (chunk) bölünerek işlenir.
Örneğin 200.000 kayıt → chunk size 1000 → 200 batch.
Böylece transaction yönetimi ve memory kullanımı optimize edilir.

Batch Update / JDBC Batch:
Update veya insert işlemleri toplu (batch) olarak veritabanına gönderilir.
Tek tek kayıt göndermek yerine, birden fazla kayıt tek seferde işlenir → performans artar.

Transaction yönetimi:
Spring Batch, her chunk için tek bir transaction yönetir.
Gereksiz commit ve rollback'leri azaltır.

Restart ve Skip mekanizması:
Hata durumunda yalnızca problemli chunk tekrar işlenir, tüm veri baştan işlenmez.

2. Performansı etkileyen faktörler

Chunk boyutu: Çok küçük → sık commit → yavaş. Çok büyük → memory problemi.
Önerilen: 500–5000 arası, veri tipine ve memory'ye göre ayarla.

Veritabanı optimizasyonu:
Index'ler, partitioning, batch insert/update destekleyen DB özellikleri.

Reader / Writer seçimi:
JDBC, JPA, Hibernate, CSV veya flat file reader hız farkı yaratır.

Parallel processing / Multi-threading:
Spring Batch, step'leri paralel çalıştırabilir. Çok büyük verilerde performans artışı sağlar.

3. Özet

→ Spring Batch tek başına "otomatik hızlı" değildir, doğru yapılandırılırsa büyük veri setlerinde çok hızlı çalışır.
→ Ana hız faktörleri: chunk size, batch update, transaction yönetimi, paralel processing ve reader/writer optimizasyonu.

Spring WebFlux ile Spring MVC arasındaki temel fark nedir?

→ Spring MVC: Thread-per-request modeli (blocking I/O).

→ Spring WebFlux: Event-loop tabanlı (non-blocking, reactive), çok daha az thread ile yüksek concurrency sağlar.

→ Kullanım senaryosu: WebFlux → yüksek trafik, streaming API'ler; MVC → klasik CRUD uygulamaları.

Reactive programming'de Mono ve Flux nedir?

→ Mono<T>: 0 veya 1 sonuç döner.

→ Flux<T>: 0…N sonuç döner (stream).

Örn: Mono<User> (tek kullanıcı), Flux<User> (çok kullanıcı).

Microservices mimarisinde Service Discovery (Eureka/Consul) neden kullanılır?

→ Servisler dinamik olarak scale olunca IP/port sabit kalmaz.

→ Eureka/Consul gibi discovery server'lar, servislerin birbirini bulmasını sağlar.

→ Örn: OrderService → UserService'in IP'sini bilmeden istek atabilir.

Spring Cloud Config Server ne işe yarar?

→ Tüm microservice'lerin konfigürasyonlarını merkezi yönetmek için kullanılır.

→ Konfigürasyonlar genellikle Git repo'da tutulur.

→ Dinamik olarak config değişimi (refresh scope) yapılabilir.

Circuit Breaker nedir? Spring Cloud ile nasıl uygulanır?

→ Amaç: Bir servis sürekli hata veriyorsa diğer servisleri korumak.

→ Resilience4j / Hystrix ile uygulanır.

→ Örn: @CircuitBreaker(name="inventoryService", fallbackMethod="fallback")

Kafka ile RabbitMQ arasındaki fark nedir?

→ Kafka: High throughput, event streaming, partition + offset bazlı, log mantığında çalışır. Gerçek zamanlı veri işleme (stream processing).

→ RabbitMQ: Message broker, queue tabanlı, daha klasik mesajlaşma.

Spring Boot'ta Kafka consumer grupları nasıl çalışır?

→ Cache olarak: @EnableCaching + @Cacheable, @CacheEvict.

→ Data structure store olarak: Hash, List, Set kullanarak (örn: alışveriş sepeti).

→ Message broker olarak: Pub/Sub mekanizması.

Reactive WebFlux + R2DBC nedir?

→ R2DBC (Reactive Relational Database Connectivity), klasik JDBC'nin reactive versiyonudur.

→ JDBC blocking çalışır → WebFlux uyumlu değil.

→ R2DBC → Non-blocking DB erişimi (Postgres, MySQL, MSSQL için destek var).

Saga Pattern nedir? Microservices'te neden kullanılır?

→ Microservices'te dağıtık transaction problemini çözmek için kullanılan pattern.

→ Her servis kendi DB'sine sahip → klasik transaction yok.

→ Saga → işlemleri adım adım yürütür, hata olursa compensating transaction ile geri alır.

→ Örn: Sipariş → Ödeme → Stok → kargo. Ödeme başarısız olursa sipariş iptal edilir.

WebFlux hangi senaryoda uygun değil?

Spring WebFlux çok güçlü ama her durumda uygun değildir. İşte detaylar:

✅ WebFlux'un güçlü olduğu alanlar

→ Çok yüksek concurrency (aynı anda binlerce request → streaming, chat, IoT).

→ Streaming API'ler (Server-Sent Events, WebSocket).

→ I/O bound işler (dosya okuma, başka servis çağırma, DB'den veri çekme).

→ Non-blocking driver'lar ile (R2DBC, Reactive Mongo, WebClient).

❌ WebFlux'un uygun olmadığı senaryolar

✅CPU-bound işler (ağır işlemci yükü)
→ Örn: görüntü işleme, büyük matematiksel hesaplar, AI model çalıştırma.
→ Çünkü WebFlux event-loop modeli kullanır → CPU'yu meşgul eden işler event-loop'u bloke eder, performans düşer.
→ Çözüm: Bu tür işleri ayrı thread pool (ör. Schedulers.boundedElastic()) üzerinde çalıştırmak.

✅Blocking API / Driver kullanımı
→ Eğer kullandığın kütüphane blocking ise (örn: klasik JDBC), WebFlux'ın faydasını kaybedersin.
→ Çünkü tek bir blocking işlem event-loop'u durdurur → diğer tüm request'ler etkilenir.
→ Çözüm: R2DBC, Reactive MongoDB, Reactive Redis gibi non-blocking driver'lar kullan.

✅Düşük concurrency, basit CRUD uygulamaları
→ Örn: Küçük bir şirket içi CRUD paneli.
→ MVC daha basittir, debugging kolaydır, community daha büyüktür.
→ WebFlux burada gereksiz karmaşıklık yaratır.

✅Transaction-heavy senaryolar (RDBMS + ACID)
→ WebFlux + R2DBC ile transaction yönetimi sınırlıdır.
→ Eğer çok karmaşık SQL transaction'ların varsa (multi-step join, distributed transaction), klasik Spring MVC + JDBC daha stabil olur.

✅Ecosystem uyumsuzluğu
→ Bazı 3rd party kütüphaneler (özellikle eski olanlar) reactive desteklemez.
→ Örn: raporlama, PDF, e-mail API'leri blocking çalışır → WebFlux'ı verimsiz hale getirir.

🎯 Özet

WebFlux = non-blocking, I/O-heavy, high concurrency uygulamalar için süper.
Spring MVC = CPU-heavy, transaction-heavy, basit CRUD için daha uygun.

Reactive WebFlux'ta backpressure nedir, nasıl yönetilir?

→ Backpressure: Publisher'ın ürettiği veri hızının, Subscriber'ın tüketme hızını aşması.

→ Yönetim yolları: onBackpressureBuffer(), onBackpressureDrop(), limitRate() gibi Reactor operatörleriyle kontrol edilir.

Reactive WebFlux'ta thread modeli nasıl çalışır?

→ WebFlux Netty event-loop modeli kullanır.

→ Default: N CPU çekirdeği için 2N thread oluşturur.

→ Request processing → event-loop threadlerinde yürür, CPU-bound işler için boundedElastic veya parallel scheduler kullanılır.

Spring Cloud Gateway ile Zuul arasındaki fark nedir?

→ Zuul 1: Servlet (blocking I/O).

→ Spring Cloud Gateway: Netty (non-blocking, reactive).

→ Gateway → route, filter, rate limiting, circuit breaker gibi modern özellikler destekler.

Distributed tracing (Zipkin/Jaeger) nasıl entegre edilir?

→ Spring Cloud Sleuth → microservice'ler arasında traceId ve spanId ekler.

→ Log'lar merkezi hale gelir, Zipkin/Jaeger UI'dan request flow izlenebilir.

→ Örn: traceId=123 spanId=456 → hangi servislerde gezdiği görülür.

Kafka'da exactly-once delivery nasıl sağlanır?

→ Producer tarafında: enable.idempotence=true.

→ Transactional producer + consumer offset commit birlikte yönetilir (transactional.id).

→ Böylece duplicate veya kayıp mesaj engellenir.

Redis Cluster ve Sentinel arasındaki fark nedir?

→ Redis Sentinel: High availability (master-slave failover).

→ Redis Cluster: Sharding + horizontal scaling.

→ Büyük verilerde Redis Cluster, yüksek availability için Sentinel.

CQRS (Command Query Responsibility Segregation) nedir, Microservices'te nasıl uygulanır?

→ Command (yazma) ve Query (okuma) işlemleri ayrı servisler/DB'ler ile yapılır.

→ Örn: Write DB (Postgres), Read DB (ElasticSearch/Redis).

→ Microservices'te performans + ölçeklenebilirlik sağlar.

Reactive Kafka (spring-kafka vs reactor-kafka) farkı nedir?

→ spring-kafka: Classic (blocking) consumer/producer API'si.

→ reactor-kafka: Kafka client'ını Reactive Streams (Flux/Mono) ile entegre eder.

→ WebFlux tabanlı uygulamalarda reactor-kafka tercih edilir.

Saga Pattern ile Choreography ve Orchestration farkı nedir?

→ Choreography: Event-driven, servisler birbirine event gönderir (loosely coupled).

→ Orchestration: Merkezi bir Saga orchestrator servis, tüm adımları yönetir.

→ Trade-off: Choreography → basit ama karmaşıklaşabilir, Orchestration → merkezi kontrol ama single point of failure riski.

Redis'i sadece cache değil, event streaming için nasıl kullanırsın?

→ Redis Streams (Kafka benzeri, log-based, consumer group destekli).

→ Event-driven microservices için hafif alternatif.

→ XADD, XREADGROUP komutları ile çalışır.

Spring Boot

Spring Boot'un temel özellikleri nelerdir?

  • Bağımsız (stand-alone) Spring uygulamaları oluşturma yeteneği.
  • Gömülü Tomcat, Jetty veya Undertow gibi servlet konteynerleri sunması.
  • Basitleştirilmiş yapılandırma (auto-configuration) sayesinde hızlı geliştirme.
  • "Opinionated" varsayılan yapılandırmalar sunarak geliştirici kararlarını azaltması.
  • Geliştirme araçları ve Actuator gibi özellikler sunarak uygulama izleme ve yönetimi kolaylaştırması.

Spring Boot'ta Auto-Configuration nasıl çalışır?

Spring Boot Auto-Configuration, projenize eklediğiniz bağımlılıkları analiz ederek, uygulamanız için gerekli olan bean'leri otomatik olarak yapılandırır. Bu işlem @EnableAutoConfiguration anotasyonu (genellikle @SpringBootApplication içinde bulunur) ile tetiklenir. Spring Boot, spring.factories dosyalarında tanımlanan AutoConfiguration sınıflarını yükler ve belirli koşullar sağlandığında bu sınıflardaki bean tanımlarını IoC konteynerine ekler.

Spring Boot Actuator'ın temel kullanım alanları nelerdir? Hangi önemli endpoint'leri sunar?

Spring Boot Actuator, çalışan bir Spring Boot uygulamasının sağlık durumu, metrikleri, yapılandırması ve diğer operasyonel bilgilerini izlemek ve yönetmek için kullanılır. Önemli endpoint'leri şunlardır:

  • /health: Uygulamanın sağlık durumunu gösterir.
  • /info: Uygulama hakkında özel bilgileri (örneğin sürüm, build bilgileri) gösterir.
  • /metrics: Uygulama metriklerini (bellek kullanımı, CPU kullanımı, HTTP istek sayıları vb.) gösterir.
  • /env: Uygulama ortam özelliklerini gösterir.
  • /beans: Spring IoC konteynerindeki tüm bean'leri listeler.
  • /configprops: @ConfigurationProperties ile tanımlanmış yapılandırma özelliklerini gösterir.
  • /mappings: Uygulamadaki tüm request mapping'lerini (endpoint'leri) listeler.
  • /loggers: Uygulamanın logger yapılandırmasını yönetmeye olanak tanır.

Spring Boot CLI (Command Line Interface) ne işe yarar?

Spring Boot CLI, Spring Boot uygulamalarını hızlı bir şekilde prototiplemek ve çalıştırmak için komut satırı araçları sunar. Özellikle basit uygulamalar veya hızlı denemeler için faydalıdır. Java kodunu derleme ve çalıştırma süreçlerini basitleştirir.

Spring Boot'ta farklı profiller nasıl yönetilir? Ne zaman kullanılırlar?

Spring Boot'ta farklı ortamlar (development, test, production vb.) için farklı yapılandırmalar tanımlamak için profiller kullanılır. application-{profilAdı}.properties veya application-{profilAdı}.yml şeklinde isimlendirilmiş yapılandırma dosyaları oluşturularak profiller tanımlanır. Uygulama başlatılırken --spring.profiles.active={profilAdı} argümanı ile veya spring.profiles.active ortam değişkeni ile aktif profil belirtilebilir.

Spring Boot'ta gömülü sunucu (embedded server) kullanmanın avantajları nelerdir?

  • Uygulamanın bağımsız bir şekilde çalıştırılabilmesi (JAR olarak paketlenebilir).
  • Dağıtımın kolaylaşması (harici bir sunucu kurulumuna gerek kalmaz).
  • Geliştirme sürecinin hızlanması (dahili sunucu ile hızlı test ve yineleme).
  • Test ortamlarının kolayca kurulabilmesi.

Spring Boot uygulamasını production ortamına nasıl deploy edersiniz? Farklı yöntemler nelerdir?

Spring Boot uygulamalarını production ortamına deploy etmek için farklı yöntemler vardır:

  • JAR olarak çalıştırma: Gömülü sunucu ile paketlenmiş JAR dosyasını java -jar komutuyla çalıştırmak.
  • WAR olarak deploy etme: Uygulamayı geleneksel bir Java EE uygulama sunucusuna (Tomcat, JBoss vb.) WAR dosyası olarak deploy etmek (bu durumda spring-boot-starter-tomcat gibi bağımlılıkların provided olarak işaretlenmesi gerekebilir).
  • Docker konteyneri: Uygulamayı bir Docker imajı içine alıp, konteyner orkestrasyon araçları (Kubernetes, Docker Swarm vb.) ile yönetmek.
  • Cloud platformlarına deploy etme: AWS, Azure, Google Cloud gibi bulut platformlarının sunduğu özel servisler (örneğin AWS Elastic Beanstalk, Azure App Service, Google Cloud Run) aracılığıyla deploy etmek.

Spring Boot'ta @Autowire ve @Qualifier ?

Bu kombinasyon türü uygulamada birçok farklı türde tekil bean bulunduğunda kullanılır. Bu kombinasyon her bir ayrı bean'i farklılaştırır.

@Autowired annotasyonu kullanıldığında Spring, bağımlılığı otomatik olarak enjekte eder. Ancak birden fazla aday bean olduğunda, hangi bean'in kullanılması gerektiğini belirtmemiz gerekiyor. İşte @Qualifier annotasyonu bu seçimi yapmamızı kolaylaştırır.

Circuat Breaker nedir ?

Circuit Breaker, bir servisin aşırı yük altında olduğunu veya düzgün çalışmadığını tespit ettiğinde, otomatik olarak o servise gelen istekleri keser. Bu sayede sistem, tek bir servisin başarısızlığından dolayı tamamen çökme durumuna düşmekten korunmuş olur.

Spring Boot Interceptor Nedir?

Interceptor, Spring MVC paketinde bulunan bir sınıftır. HTTP isteklerinin öncesi, sonrası ve tamamlandıktan sonra yapılması gereken işlemleri bu sınıf aracılığı ile handle edebilmekteyiz.

Gelen isteklerin endpointe ulaşmadan önce işlenmesini sağlamamıza yarayan bir sınıftır. Bir servlete benzer ve DispatcherServlet ten sonra bulunmaktadır. HTTP isteklerini kontrol etmek için kullanılır. İstek başlamadan önce çağrılır ve HTTP isteği ile ilgili bilgileri içeren HttpServletRequest nesnesini ve HTTP isteği ile ilgili yanıtı döndürecek HttpServletResponse nesnesini alır.

Spring IOC Container ?

Spring IoC Container, Spring Framework'ün çekirdeğidir. Bu konteyner, nesneleri oluşturur, nesneleri birbirine bağlar, bağımlılıklarını yapılandırır ve tüm yaşam döngüsünü yönetir.

Inversion of control bir yazılım tasarım prensibidir. Ioc ile Uygulama içerisindeki obje instance'larının yönetimi sağlanarak, bağımlılıklarını en aza indirgemek amaçlanmaktadır. Projenizdeki bağımlılıkların oluşturulmasını ve yönetilmesini geliştiricinin yerine, framework'ün yapması olarak da açıklanır.

Framework'ün üzerinde çalıştığımız da görülüyor ki; frameworkler birçok işi kendisi yapmakta ve bizim kodumuzu çalıştırmak için framework gerekli kaynakları ve çalışması gereken metotları oluşturup, yönetmektedir. Yazdığımız kod bloğu çalışacağı zaman, framework bizim kodumuzu çağırır ve çalıştırır daha sonra kontrol yeniden framework'e geçmesi olayının tümüne Inversion Of Control adı verilmektedir.

Spring Scope Türleri nelerdir?

Spring Framework içinde "scope" bir nesnenin yaşam döngüsünü ve ne kadar süreyle erişilebilir olduğunu tanımlayan bir kavramdır. Spring, çeşitli nesne scope'ları sağlar ve bu scope'lar nesnelerin oluşturulma, kullanılma ve yok edilme şeklini belirler.

Bu scope'lar, Spring uygulamalarında nesnelerin nasıl yönetileceğini belirlemek için kullanılır. Scope belirleme, nesnelerin doğru zamanda oluşturulması, paylaşılması ve yok edilmesi açısından önemlidir ve uygulamanın performansı ve davranışı üzerinde etkili olabilir.

singleton Scope

Bir bean default olarak singleton scope'a sahiptir. Bean singleton scope ile tanımlandığı zaman mevcut application context'imiz içerisinde o bean'den yalnızca tek bir adet initialize edileceğini garanti ederiz. Bu bean ile yapılacak olan tüm request'ler cache'lenmiş olan aynı nesne üzerinden yapılır.

prototype Scope

Prototype ile belirlenmiş bir bean, container içerisinde çağırıldığı her request'te yeniden oluşturulacaktır. Scope notasyonun iki farklı kullanımını aşağıda görebilirsiniz.

Prototype Scope kullandığınızda, her request geldiğinde yeni bir instance döndürür. Diyelim ki bir setter methoduna sahip bir sınıfınız var, şimdi bu sınıf için bir bean oluşturduğunuzda, size her zaman sınıfın yeni bir instance'sını verecek ve nesne niteliklerini değiştirmek için setter'ı özgürce kullanıp çalışacaktır.

request Scope

Request bean'i HTTP isteği geldiğinde oluşturulur. örneğin, bir " /products" API'niz var, şimdi controller bu isteği aldığında ve service methodunu çağırdığında, Request Scope ile bir Bean'iniz olacak ve bu API isteği yanıtı geri gönderene kadar her zaman nesnenin aynı instance'ını alırsınız, ancak yeni bir request geldiğinde, yeni bir instance gönderecek.

session Scope

Session Scope Web Uygulamalarında HTTP isteği geldiğinde oluşturulur. Mesela Spring boot uygulamanız kullanıcı sessionlarını sürdürdüğünde, bu scope yardımcı olabilir.

Session Scope kullandığımızda, tüm Session için (kullanıcı düzeyindeki oturumda) her zaman nesnenin aynı instance'ını return eder. Ancak kullanıcı oturumu kapandığında, yeni bir kullanıcı oturumu için nesnenin yeni bir instance'ını alacaksınız.

application Scope

Bir application scope, ServletContext'in yaşam döngüsü için bean örneğini oluşturur. Bu singleton scope'a benzer ancak aralarında farklılıklar mevcuttur. Bir bean application scope değerine sahipken bu bean çoklu servlet tabanlı uygulamalar ile de paylaşılabilirken, singleton scope değerine sahip bir bean yalnızca mevcut application context'i içerisinde tanımlıdır.

Spring Cloud

Spring Cloud nedir ve mikroservis mimarisindeki rolü nedir?

Spring Cloud, mikroservis mimarisi oluşturmayı kolaylaştıran bir dizi araç ve kütüphane sağlayan bir şemsiye projedir. Mikroservisler arasındaki iletişimi, yapılandırma yönetimini, servis keşfini, devre kesici (circuit breaker) mekanizmalarını, API ağ geçidini ve daha birçok dağıtık sistem sorununu çözmek için çözümler sunar.

Spring Cloud Config Server ne işe yarar? Avantajları nelerdir?

Spring Cloud Config Server, mikroservis uygulamalarının merkezi bir yerden yapılandırılmasını sağlayan bir servistir. Git, SVN veya HashiCorp Vault gibi farklı backend'lerden yapılandırma bilgilerini okuyabilir ve istemci mikroservislere HTTP üzerinden sunar. Avantajları şunlardır:

  • Yapılandırma yönetimini merkezileştirir.
  • Yapılandırma değişikliklerinin tüm servislere kolayca yayılmasını sağlar.
  • Sürüm kontrolü ve yapılandırma geçmişi tutulabilir.
  • Güvenli yapılandırma yönetimi imkanı sunar.

Spring Cloud Netflix Eureka nedir ve mikroservislerde servis keşfi (service discovery) için nasıl kullanılır?

Spring Cloud Netflix Eureka, mikroservislerin birbirlerini bulmasını sağlayan bir servis keşfi sunucusudur. Her mikroservis, başlatıldığında Eureka Server'a kendi adres ve port bilgilerini kaydeder. Diğer mikroservisler de Eureka Server'a danışarak ihtiyaç duydukları servisin konumunu öğrenir ve iletişim kurarlar. Bu sayede servislerin dinamik olarak ölçeklenmesi ve yer değiştirmesi kolaylaşır.

Spring Cloud Gateway nedir ve mikroservis mimarisinde ne gibi roller üstlenir?

Spring Cloud Gateway, mikroservisler için bir API ağ geçidi (API Gateway) görevi gören bir projedir. Temel rolleri şunlardır:

  • Tek bir giriş noktası sağlayarak istemcilerin mikroservislere erişimini kolaylaştırır.
  • Yönlendirme (routing) kurallarını yönetir.
  • Güvenlik (authentication, authorization) gibi kesen ilgileri merkezi olarak yönetebilir.
  • Hız sınırlaması (rate limiting), devre kesici (circuit breaking) gibi özellikleri uygulayabilir.
  • İstek ve cevapları dönüştürebilir.

Spring Cloud Circuit Breaker (örneğin Resilience4j) ne işe yarar? Hangi sorunları çözmeye yardımcı olur?

Spring Cloud Circuit Breaker (Resilience4j gibi kütüphaneler aracılığıyla), dağıtık sistemlerde servisler arasındaki iletişimde olası hatalara karşı dayanıklılığı artırmak için kullanılır. Bir servis çağrısı belirli bir eşiği aşan sayıda başarısız olursa, devre kesici açılır ve bir süre boyunca hatalı servise yapılan çağrıları engeller. Bu sayede sistemin tamamının çökmesi önlenir ve hatalı servisin iyileşmesi için zaman tanınır.

Spring Cloud Load Balancer mikroservisler arasındaki yük dengelemesini nasıl sağlar?

Spring Cloud Load Balancer, Eureka gibi bir servis keşfi mekanizmasıyla entegre olarak çalışır. Bir istemci bir servise istek gönderdiğinde, Load Balancer mevcut olan servis örnekleri arasından birini seçerek isteği yönlendirir. Bu, yükün birden fazla servis örneğine eşit olarak dağıtılmasını sağlar ve tek bir servis örneğinin aşırı yüklenmesini önler. Farklı yük dengeleme algoritmaları (round-robin, random, weighted response time vb.) desteklenebilir.

Spring Cloud Stream nedir ve mikroservisler arasında asenkron iletişimi nasıl kolaylaştırır?

Spring Cloud Stream, mikroservisler arasında olay güdümlü (event-driven) ve asenkron iletişimi basitleştiren bir framework'tür. Kafka, RabbitMQ gibi farklı mesajlaşma aracıları (message broker) için soyut bir katman sağlar. Mikroservisler, Spring Cloud Stream'in sağladığı binder'lar aracılığıyla mesaj kuyruklarına kolayca mesaj gönderebilir ve mesajları dinleyebilirler. Bu, servisler arasındaki bağımlılığı azaltır ve daha ölçeklenebilir ve esnek sistemler oluşturmaya olanak tanır.

Microservices ler arası iletişim kurma yöntemleri nelerdir?

  • RestTemplate: Spring'in HTTP istemci sınıfıdır. Senkron HTTP istekleri yapmak için kullanılır.
  • Feign Client: Netflix tarafından geliştirilen ve Spring Cloud entegre ettiği bir HTTP istemcisidir. Deklaratif bir yaklaşım sunar ve arka planda RestTemplate veya WebClient kullanır.
  • GRPC: Google tarafından geliştirilen yüksek performanslı, açık kaynaklı bir RPC (Remote Procedure Call) framework'üdür. HTTP/2 kullanır ve Protocol Buffers ile veri serileştirme yapar.

Mikroservisler

Monolitik mimari ile mikroservis mimarisinin temel farkları nelerdir? Mikroservislerin avantaj ve dezavantajları nelerdir?

Monolitik Mimari: Tüm uygulama tek bir büyük kod tabanı ve tek bir dağıtım birimi olarak geliştirilir.

Mikroservis Mimarisi: Uygulama, bağımsız olarak dağıtılabilen küçük, özel amaçlı servislerden oluşur. Her servis kendi veritabanına ve teknoloji yığınına sahip olabilir.

Mikroservislerin Avantajları:

  • Teknolojik Çeşitlilik: Farklı servisler farklı teknolojilerle geliştirilebilir.
  • Ölçeklenebilirlik: Her servis bağımsız olarak ölçeklenebilir.
  • Hızlı Geliştirme ve Dağıtım: Küçük ve bağımsız servisler daha hızlı geliştirilip deploy edilebilir.
  • Hata İzolasyonu: Bir servisteki hata diğer servisleri etkilemez.
  • Daha İyi Organizasyon: Küçük, odaklanmış ekipler tarafından geliştirilebilir.

Mikroservislerin Dezavantajları:

  • Dağıtık Sistem Karmaşıklığı: Servisler arası iletişim, ağ sorunları, dağıtık veri yönetimi gibi zorluklar ortaya çıkar.
  • Operasyonel Yük: Daha fazla sayıda servis yönetmek gerekir.
  • İzleme ve Hata Ayıklama Zorluğu: Dağıtık sistemlerde izleme ve hata ayıklama daha karmaşıktır.
  • Servisler Arası İletişim Yönetimi: Etkili ve performanslı servisler arası iletişim mekanizmaları (REST, gRPC, mesajlaşma) gereklidir.

Mikroservisler arası iletişimde kullanılan yaygın yöntemler nelerdir? Avantaj ve dezavantajlarını karşılaştırınız.

Yaygın iletişim yöntemleri şunlardır:

REST (Synchronous): HTTP protokolü üzerinden yapılan senkron iletişimdir. Basit ve yaygın olarak kullanılır.

Dezavantajı: Servisler arasındaki sıkı bağlılık ve olası performans sorunlarıdır.

Mesajlaşma (Asynchronous): Kafka, RabbitMQ gibi mesaj kuyrukları aracılığıyla yapılan asenkron iletişimdir.

Avantajları: Daha gevşek bağlılık, daha iyi ölçeklenebilirlik ve güvenilirlik sağlar.

Dezavantajı: Karmaşıklık ve eventual consistency (sonunda tutarlılık) sorunlarıdır.

gRPC (Synchronous/Asynchronous): Google tarafından geliştirilen yüksek performanslı, dil bağımsız bir RPC framework'üdür. Protobuf ile veri serileştirme kullanır.

Avantajları: Yüksek performans ve güçlü tip güvenliği sunar.

Dezavantajı: Bazı platformlarda ve dillerde daha az yaygın olmasıdır.

Mikroservislerde veri yönetimi nasıl ele alınır? Her servis kendi veritabanına sahip olmanın avantajları nelerdir?

Mikroservislerde genellikle her servis kendi bağımsız veritabanına sahiptir (database per service pattern). Bunun avantajları şunlardır:

  • Teknolojik Özgürlük: Her servis kendi ihtiyaçlarına en uygun veritabanı teknolojisini seçebilir.
  • İzolasyon: Bir servisteki veri modeli veya şemasındaki değişiklikler diğer servisleri etkilemez.
  • Ölçeklenebilirlik: Her veritabanı servisin ihtiyaçlarına göre bağımsız olarak ölçeklenebilir.
  • Daha İyi Performans: Her servis kendi veri erişimini optimize edebilir.

Ancak bu yaklaşım, dağıtık işlemler (distributed transactions) gibi veri tutarlılığı sorunlarını da beraberinde getirebilir. Bu sorunları çözmek için Saga pattern gibi yaklaşımlar kullanılabilir.

Mikroservislerde distributed tracing (dağıtık izleme) neden önemlidir? Hangi araçlar kullanılabilir?

Mikroservislerde distributed tracing, bir isteğin birden fazla servis üzerinden geçerkenki yolunu ve her bir serviste harcadığı süreyi izlemek için kritik öneme sahiptir. Bu, performans sorunlarını tespit etmek, hataları ayıklamak ve sistemin genel davranışını anlamak için gereklidir.

Kullanılabilecek araçlar arasında Zipkin, Jaeger ve Spring Cloud Sleuth (çeşitli tracing backend'lerini destekler) bulunur.

API Gateway mikroservis mimarisinde neden gereklidir? Temel sorumlulukları nelerdir?

API Gateway, mikroservis mimarisinde istemciler için tek bir giriş noktası sağlayarak karmaşıklığı azaltır. Temel sorumlulukları şunlardır:

  • Yönlendirme (Routing): Gelen istekleri uygun mikroservislere yönlendirmek.
  • Güvenlik (Authentication ve Authorization): Kimlik doğrulama ve yetkilendirme işlemlerini merkezi olarak yönetmek.
  • Hız Sınırlaması (Rate Limiting): Servislerin aşırı yüklenmesini önlemek için istek hızını kontrol etmek.
  • İstek ve Cevap Dönüşümü: İstemci ve servisler arasındaki veri formatlarını dönüştürmek.
  • Önbellekleme (Caching): Sık erişilen verilere daha hızlı erişim sağlamak.
  • İzleme ve Günlükleme: İstekleri ve cevapları izlemek ve loglamak.

Mikroservis mimarisinde "Contract Testing" ve "End-to-End Testing" arasındaki fark nedir? Neden önemlidirler?

Contract Testing (Kontrat Testi): Bir servis sağlayıcısının (provider) sunduğu API kontratının (istek ve cevap formatları) tüketicisi (consumer) tarafından beklendiği gibi olduğunu doğrular. Amaç, servisler arasındaki entegrasyon sorunlarını erken aşamada tespit etmektir.

End-to-End Testing (Uçtan Uca Test): Tüm sistemin veya belirli bir iş akışının baştan sona doğru çalıştığını doğrular. Birden fazla servisin etkileşimini ve genel sistem davranışını test eder.

İkisi de önemlidir çünkü Contract Testing servisler arası uyumluluğu sağlarken, End-to-End Testing sistemin genel işlevselliğini doğrular. Birbirini tamamlarlar ve birlikte kullanıldıklarında daha güvenilir mikroservis sistemleri oluşturulur.

3. part bir servise istek attığında hata alırsan yapılan işlemleri nasıl geri alırsın?

Bu durumda Saga pattern kullanılabilir. Saga pattern, dağıtık sistemlerde birden fazla servis arasında gerçekleşen işlemlerin tutarlılığını sağlamak için kullanılan bir desendir.

Saga pattern iki şekilde uygulanabilir:

  1. Choreography-based Saga: Her servis, kendi işlemini tamamladıktan sonra bir olay (event) yayınlar. Diğer servisler bu olayları dinleyerek kendi işlemlerini gerçekleştirir. Bir hata durumunda, ilgili servisler compensating transaction (telafi edici işlem) yayınlar.
  2. Orchestration-based Saga: Merkezi bir orchestrator servis tüm işlemleri yönetir. Her adımı sırayla çalıştırır ve bir hata durumunda, daha önce tamamlanan adımları geri almak için compensating işlemleri tetikler.

Örneğin, bir sipariş işlemi düşünün: Sipariş servisi → Ödeme servisi → Stok servisi → Kargo servisi. Eğer ödeme servisinde bir hata oluşursa, Saga pattern sipariş servisini iptal ederek işlemleri geri alır.

CQRC nedir?

CQRS (Command Query Responsibility Segregation), bir yazılım tasarım desenidir ve komut (command) ile sorgu (query) sorumluluklarını ayırmayı temel alır. Bu desen, özellikle karmaşık iş uygulamalarında performansı, ölçeklenebilirliği ve güvenliği artırmak için kullanılır.

CQRS'de:

  • Command (Komut): Veriyi değiştiren işlemler (create, update, delete). Bu işlemler genellikle write model üzerinde çalışır.
  • Query (Sorgu): Veriyi okuyan işlemler (select). Bu işlemler read model üzerinde çalışır.

CQRS'nin temel avantajları:

  • Okuma ve yazma işlemleri için farklı veri modelleri kullanılabilir, bu da her iki işlem için en uygun yapıyı oluşturmayı sağlar.
  • Okuma ve yazma işlemleri bağımsız olarak ölçeklenebilir.
  • Karmaşık sorgular için optimize edilmiş read model oluşturulabilir.
  • Güvenlik açısından, komut ve sorgu işlemleri için farklı yetkilendirme kuralları uygulanabilir.

Apache Kafka ve Rabbit MQ arasındaki farklar nelerdir?

Apache Kafka:

  • Distributed streaming platform olarak tasarlanmıştır.
  • Yüksek verimlilik (high throughput) ve düşük gecikme (low latency) sağlar.
  • Verileri kalıcı olarak depolar ve mesajların yeniden işlenmesine olanak tanır.
  • Partitioning ve replication ile yüksek ölçeklenebilirlik ve hata toleransı sunar.
  • Event sourcing ve stream processing senaryoları için uygundur.

RabbitMQ:

  • Geleneksel bir mesajlaşma kuyruğu sistemidir.
  • Karmaşık yönlendirme (routing) senaryolarını destekler.
  • Farklı mesajlaşma protokollerini (AMQP, MQTT, STOMP) destekler.
  • Esnek exchange ve queue yapıları sunar.
  • İş akışı yönetimi ve görev kuyruğu (task queue) senaryoları için uygundur.

Özetle, Kafka büyük veri akışları ve olay kaynaklı mimariler için daha uygunken, RabbitMQ karmaşık yönlendirme gerektiren mesajlaşma senaryoları için daha uygundur.

Saga Pattern nedir?

Saga Pattern, dağıtık sistemlerde birden fazla servis arasında gerçekleşen işlemlerin tutarlılığını sağlamak için kullanılan bir desendir. Özellikle mikro servis mimarilerinde, ACID işlemlerinin kullanılamadığı durumlarda alternatif olarak kullanılır.

Saga Pattern iki şekilde uygulanabilir:

  1. Choreography-based Saga: Her servis, kendi işlemini tamamladıktan sonra bir olay (event) yayınlar. Diğer servisler bu olayları dinleyerek kendi işlemlerini gerçekleştirir. Bir hata durumunda, ilgili servisler compensating transaction (telafi edici işlem) yayınlar.
  2. Orchestration-based Saga: Merkezi bir orchestrator servis tüm işlemleri yönetir. Her adımı sırayla çalıştırır ve bir hata durumunda, daha önce tamamlanan adımları geri almak için compensating işlemleri tetikler.

Saga Pattern'in avantajları:

  • Dağıtık sistemlerde veri tutarlılığını sağlar.
  • Servisler arası bağımlılığı azaltır.
  • Hata durumunda sistem tutarlılığını korur.
  • Uzun süreli işlemleri yönetmek için uygundur.

Domain Driven Design (DDD) ?

Domain Driven Design (DDD), karmaşık iş gereksinimlerine sahip yazılım sistemlerini tasarlamak için kullanılan bir yaklaşımdır. Eric Evans tarafından geliştirilen bu yaklaşım, yazılım geliştirmeyi iş alanındaki (domain) kavramlar ve kurallar etrafında merkezileştirir.

DDD'nin temel bileşenleri:

  • Domain: İş probleminin çözüldüğü alan.
  • Subdomain: Domain'in daha küçük parçalara ayrılması.
  • Bounded Context: Belirli bir domain modelinin geçerli olduğu sınırlı bağlam.
  • Entity: Kimliği olan ve yaşam döngüsü boyunca takip edilen nesneler.
  • Value Object: Kimliği olmayan, özelliklerine göre eşitliği kontrol edilen nesneler.
  • Aggregate: Birbirine bağlı entity ve value object'lerden oluşan küme.
  • Repository: Aggregate'lerin saklanması ve geri alınması için kullanılan arayüz.
  • Domain Service: Birden fazla aggregate arasında yer alan iş mantığını içeren servisler.
  • Domain Event: Domain'de meydana gelen önemli olaylar.

DDD, özellikle mikro servis mimarilerinde servislerin sınırlarını belirlemek ve her servisin kendi domain modelini oluşturmak için kullanılır.

Veritabanı

PostgreSQL de index türleri ?

BTREE Index

Bir index yaratıldığında tipi verilmez ise default olarak btree oluşturulmaktadır. Özellikle "büyüktür", "büyük eşittir", "küçüktür", "küçük eşittir", "eşittir", "between", "is null", "is not null" gibi sorguların hepsinde kullanılabilir. Like'lı ifadeler ise "sabit değer%" şeklinde ise kullanılabilir. Balance tree algoritmasını kullanmaktadır.

  • Çoğu sorgu türü için en performanslı seçenektir.">, >=, <, <=,=, IN, BETWEEN" gibi gibi..
  • Varsayılan/Default sorgu tipidir.
  • Çoklu kolon indexlemesini yapılabilir.

Hash Index

Hash daha çok eşitlik anında kullanılabilen bir index türüdür. Oluşum hızı index yaratma süresi açısından Btree'ye göre çok daha fazladır. Ancak kapladığı alan bakımından Btree'ye göre çok daha az bir yer kaplar. Çünkü Btree ağaç yapısında tutulurken, hash flat bir yapıda tutulmaktadır.

Hash index, kullanım şekli açısından genellikle B-tree ile karşılaştırılmaktadır.

  • Eşitlik operatörü ile yapılan sorgular için iyi bir seçenektir.
  • Hash index, B-Tree indexinden daha az yer kaplar.
  • Tabloya satırlar eklendikçe linear olarak büyüyen B-Tree indexinin aksine, Hash indexi ani artışlarla büyür.
  • Hash indexler ile "unique" constraint kullanılamaz.
  • Hash indexler birden fazla kolon için oluşturulamazlar.
  • Hash indexleme yapılırken sıralama ifadelerine yer verilemez.
  • Hash indexleme yaptığınız bir tablo için Cluster kullanamazsınız.

BRIN: Block range index

Postgresql verileri varsayılan olarak 8 Kb'lık bloklar halinde saklamaktadır. Brin indexlemede, indexler tutulurken bloklar içerisindeki en büyük ve en küçük değerler baz alınır. B-tree'nin aksine blok içersinde sıralanmış tüm değerler değil, sadece min ve max değerler tutulur. Eski adıyla min-max indextir.

B-tree yaratıldığında 8Kb'lık veri setlerinin tümünü saklayacak şekilde bir indexleme yapar. Ancak BRIN ındex 8Kb'lık bloklardan sadece minumum ve maximum değerleri alarak index halinde saklar.

  • Btree ile karşılaştırıldığında tutalan veri boyutuna bakarsak çok çok daha az olduğunu görebiliriz.
  • Doğrudan bir veri yerine bir aralık üzerinde işlem yapılıyorsa çok performanslı çalışabilir.
  • Sadece belirli veriler index için tutulduğundan ötürü en az yer kaplayan index türüdür.
  • Özellikle big data ve veri analizi alanlarında range işlemlerinin çokluğundan dolayı tercih edilmektedir.

Gin Index

Generalized Inverted Index ile her kelime için bir index ve bu indexin içinde aranan ifadenin geçtiği yerlerin listesini sıkıştırılmış olarak tutar.

  • Bir kolonda array gibi çoklu verinin olması durumlarında kullanılabilir. Yani metin içinde aramalarda kullanılması önerilir
  • "Full text search" işlerinde kullanılabilir.
  • JSONB üzerinde yapılan aramalarda tercih edilebilir.
  • Range ve array veri tiplerinde kullanılabilir
  • ILIKE ile birlikte '%abc%' şeklindeki aramalarda btree verimli çalışmaz. GIN tercih edilebilir.

GIST Index

Generalized search tree, full text search için güçlü diğer bir adaydır. Btree karşılaştırma yapıları için kullanılırken, GIST'te ağaç yapısında veri tutmasına karşın daha çok modern veritabanlarındaki geodata, text documents gibi operatorler için kullanılmaktadır.

  • Aynı kolonda değerlerin başka satırlarda çakışması durumlarında kullanılabilir.
  • Indexleme yöntemidir ve bu index tipinden birçok index türetilebilir.
  • "Full text search" işlerinde kullanılabilir.
  • Geometrik veri türlerini indexlemek için kullanılırlar.

Optimistic Lock Nedir ?

Optimistic, yani iyimser eş zamanlılık kontrolünde aynı anda bir kaydın update edilmeyeceği varsayılır ve birden fazla session aynı kaydı update etmek için erişebilir. Eğer aynı kayıt birden fazla kişi tarafından update edilirse kayıtlardan biri iptal olur ve kullanıcıya iptal olduğuna dair bilgilendirme yapılır.

Pessimistic Lock Nedir ?

Pessimistic, yani kötümser eş zamanlılık kontrolünde bir kullanıcı bir kaydı değiştirmek istediğinde o kayda kilit koyar ve o kaydı başkası değiştiremez. İlk değiştirmeye çalışan kişi kaydı değiştirdikten sonra değiştirilen kayıt üzerindeki kilit açılır ve diğer değiştirmek isteyenler artık değiştirebilir hale gelir.

Transaction İsolation ?

Transaction isolation, veritabanı sistemlerinde birden fazla transaction'ın aynı anda çalıştığı durumlarda, bu transaction'ların birbirlerini nasıl etkilediğini kontrol etmek için kullanılan bir mekanizmadır. Amaç, transaction'ların birbirlerini izole ederek veri tutarlılığını sağlamaktır.

ANSI/ISO SQL standardı dört farklı isolation seviyesi tanımlar:

  1. Read Uncommitted: En düşük izolasyon seviyesidir. Bir transaction, başka bir transaction tarafından henüz commit edilmemiş değişiklikleri okuyabilir. Bu durum "dirty read" olarak bilinir.
  2. Read Committed: Bir transaction, sadece commit edilmiş değişiklikleri okuyabilir. Bu seviyede dirty read'ler önlenir, ancak non-repeatable read'ler (aynı transaction içinde aynı verinin farklı değerlerini okuma) olabilir.
  3. Repeatable Read: Bir transaction içinde aynı veri birden fazla kez okunduğunda, her zaman aynı değerin döndürülmesi sağlanır. Bu seviyede dirty read ve non-repeatable read'ler önlenir, ancak phantom read'ler (yeni kayıtların görünmesi) olabilir.
  4. Serializable: En yüksek izolasyon seviyesidir. Transaction'lar sanki tek tek çalışıyormuş gibi davranır. Bu seviyede dirty read, non-repeatable read ve phantom read'ler önlenir.

Her izolasyon seviyesinin performans üzerinde farklı etkileri vardır. Daha yüksek izolasyon seviyeleri daha fazla tutarlılık sağlar ancak genellikle daha düşük performansla sonuçlanır.

Oracle Explain Plan Kullanımı ?

Oracle Explain Plan, bir SQL sorgusunun nasıl çalıştırılacağını gösteren bir execution plan oluşturmak için kullanılan bir araçtır. Bu plan, Oracle optimizatörünün sorguyu nasıl çalıştıracağını, hangi index'leri kullanacağını, hangi tablolara erişeceğini ve işlem maliyetini gösterir.

Explain Plan kullanımı:

  1. SQL sorgusunun önüne EXPLAIN PLAN FOR ekleyerek plan oluşturulur.
  2. PLAN_TABLE adında geçici bir tabloya plan kaydedilir.
  3. DBMS_XPLAN.DISPLAY fonksiyonu ile plan görüntülenir.
EXPLAIN PLAN FOR
SELECT * FROM employees WHERE department_id = 10;

SELECT * FROM TABLE(DBMS_XPLAN.DISPLAY);

Explain Plan çıktısı şu bilgileri içerir:

  • İşlem adımları ve sırası
  • Kullanılan erişim yolları (full table scan, index scan vb.)
  • Her adımın tahmini maliyeti
  • Estimat edilen satır sayısı
  • Kullanılan index'ler
  • Join yöntemleri

Explain Plan, sorgu performansını analiz etmek ve optimize etmek için güçlü bir araçtır. Yavaş çalışan sorguların nedenlerini anlamak ve performansı artırmak için kullanılır.

Hibernate

Hibernate Nedir ?

Hibernate yazılım nesnelerin, ilişkisel veri tabanlarındaki (relational databases) kayıtlara nasıl karşılık geldiğini yürüten bir teknolojidir.

Java programlama dilinde kullanılan açık kaynaklı bir nesne/ilişkisel eşleme (ORM) aracıdır. Hibernate, veri tabanı işlemlerini, Java sınıfları arasında doğrudan ilişki kurmak yerine nesnelerin saklanması ve yönetilmesi yoluyla yönetir.

Hibernate FetchType EAGER - LAZY Farkları ?

FetchType: Aralarında ilişki bulunan entitylerden bir tarafı yüklerken diğer tarafın yüklenme stratejisini belirlememize olanak sağlar.

EAGER kullanırsak nesneyi veritabanından çekerken EAGER olan tüm nesneleri de beraberinde çekeriz.

LAZY kullanırsak, ihtiyaç duyduğumuzda ilgili veriler çekilecektir.

Hibernate'de Lazy Loading nedir ve nasıl çalışır ?

Lazy Loading, bir nesnenin ilişkili nesnelerinin ihtiyaç duyulduğunda, yani erişildiğinde yüklenmesi yöntemidir. Bu, gereksiz veri yüklemeyi önlemek ve performansı artırmak için kullanılır. Hibernate, proxy nesneleri veya bytecode enhancement kullanarak lazy loading'i gerçekleştirir.

Örneğin, bir Customer nesnesi ve bu müşteriye ait Order nesneleri arasında bir ilişki olduğunu düşünelim. Lazy Loading kullanıldığında, Customer nesnesi yüklendiğinde Order nesneleri hemen yüklenmez. Sadece Customer nesnesine erişildiğinde Order nesneleri de yüklenir.

Hibernate'de @Entity ve @Table annotasyonlarının farkı nedir?

@Entity: bir sınıfın bir veritabanı tablosuna karşılık geldiğini Hibernate'e belirtir.

@Table: sınıfın eşleştirildiği tablonun adını ve isteğe bağlı olarak schema adını belirlemek için kullanılır.

@Entity zorunludur, ancak @Table kullanımı isteğe bağlıdır; eğer kullanılmazsa, sınıf adı tablo adı olarak varsayılır.

Hibernate'de Optimistic ve Pessimistic Kilitlenme nedir?

Optimistic Kilitlenme, veri çakışmalarını önlemek için sürüm numarası veya zaman damgası kullanır. Veri güncellenmeden önce, sürüm numarası veya zaman damgasının değişip değişmediği kontrol edilir.

Pessimistic Kilitlenme ise, bir kaynağa erişim sırasında veritabanı seviyesinde kilit kullanır, böylece diğer işlemler o kaynağı değiştiremez veya okuyamaz.

Optimistic kilitlenme genellikle okuma yoğun uygulamalarda tercih edilirken, Pessimistic kilitlenme yazma yoğun işlemlerde veya yüksek çakışma riski olan durumlarda kullanılır.

Hibernate'de cascade türleri nelerdir ve nasıl kullanılır ?

Hibernate'de cascade türleri, bir nesne üzerinde yapılan işlemlerin ilişkili nesnelere nasıl uygulanacağını belirler. Ana cascade türleri: ALL, PERSIST, MERGE, REMOVE, REFRESH, DETACH.

Örneğin, bir Parent nesnesi Child nesneleri ile bir ilişki içindeyse ve Parent nesnesi kaydedildiğinde (PERSIST) veya güncellendiğinde (MERGE) Child nesnelerinin de otomatik olarak kaydedilmesi veya güncellenmesi isteniyorsa, ilgili cascade türü ilişkide belirtilir.

Hibernate Query Plan Cache nedir ve performans üzerindeki etkisi nedir?

Hibernate Query Plan Cache, sorgu planlarını önbelleklemek için kullanılır. Bu, aynı sorgunun tekrar tekrar çalıştırılması durumunda, sorgu derleme süresini azaltarak performansı artırır. Önbellek, sorgu metni ve bağlamı (örneğin, parametre türleri) bazında sorgu planlarını saklar. Bu özellik, özellikle karmaşık sorguların ve sık çalıştırılan sorguların olduğu uygulamalarda önemli performans iyileştirmeleri sağlayabilir.

Hibernate'de N+1 sorgu problemi nedir ve nasıl çözülür?

N+1 sorgu problemi, bir entity ve onun ilişkili nesnelerini yüklerken ortaya çıkan bir performans sorunudur. Örneğin, bir Parent entity'si ile ilişkili çok sayıda Child entity'sini yüklerken, ilk olarak Parent entity'si için bir sorgu çalıştırılır ve ardından her bir Child için ayrı ayrı sorgular çalıştırılır. Bu, toplamda 1 (parent için) + N (N child için) sorgu anlamına gelir ve özellikle N'nin büyük olduğu durumlarda ciddi bir performans düşüklüğüne yol açabilir.

Bu sorunu çözmek için:

  • Fetch Join kullanarak ilişkili nesneleri tek bir sorguda yüklemek
  • Batch Fetching ile ilişkili nesneleri gruplar halinde yüklemek
  • Subselect fetching kullanmak
  • EntityGraph ile yüklenmesi gereken ilişkileri belirtmek

@Transactional` nedir? Ne işe yarar?

  • Spring Framework tarafından sağlanan bir transaction yönetim anotasyonudur.
  • Veritabanı üzerinde birden fazla SQL işlemi yapıldığında, hepsinin tek bir bütün olarak çalışmasını sağlar.
  • İşlem başarılı olursa commit, hata olursa rollback yapılır.
  • Hibernate ve JPA ile çalışırken veri tutarlılığını korumak için kullanılır.

Örneğin:


@Service
public class UserService {

    @Autowired
    private UserRepository userRepository;

    @Transactional
    public void createUserAndAccount(
        User user, 
        Account account) {

        userRepository.save(user);
        if (account.getBalance() < 0) {
            throw new RuntimeException("Hatalı bakiye!"); 
        } 
    } 
}

                                

@Transactional Parametreleri Propagation

Transaction yayılım davranışını belirler. Varsayılan: Propagation.REQUIRED

  • REQUIRED : Mevcut transaction varsa onu kullanır, yoksa yeni açar.
  • REQUIRES_NEW : Her zaman yeni transaction açar. Mevcut varsa askıya alır.
  • MANDATORY : Transaction yoksa exception fırlatır.
  • SUPPORTS : Transaction varsa kullanır, yoksa transaction olmadan çalışır.
  • NOT_SUPPORTED : Transaction varsa askıya alır, işlemi transaction olmadan yapar.
  • NEVER : Transaction olmadan çalışır, eğer varsa exception atar.
  • NESTED : Mevcut transaction içinde nested transaction açar.

Örneğin:


@Transactional(propagation = Propagation.REQUIRES_NEW)
public void saveLog(Log log) {
    logRepository.save(log);
}
                    
                                                    

@Transactional Parametreleri Isolation

  • Transaction izolasyon seviyesini belirler. Kirli okuma, tekrar eden okuma ve phantom read problemlerini kontrol eder.
  • DEFAULT : DB'nin varsayılan ayarını kullanır.
  • READ_UNCOMMITTED : Kirli okumalara izin verir.
  • READ_COMMITTED : Sadece commit edilmiş verileri okur.
  • REPEATABLE_READ : Transaction boyunca aynı satırı hep aynı görür.
  • SERIALIZABLE : En yüksek seviye, tüm transaction'lar sırayla çalışır.

Örneğin:


@Transactional(isolation = Isolation.SERIALIZABLE)
public void transferMoney(
    Long fromId, 
    Long toId, 
    double amount) {
    // En katı izolasyon seviyesi ile çalışır
}
                                        
                                                                        

@Transactional Parametreleri rollbackFor ve noRollbackFor

  • rollbackFor : Belirtilen exception oluşursa rollback yapılır.
  • noRollbackFor : Belirtilen exception oluşursa rollback yapılmaz.

Örneğin:


@Transactional(rollbackFor = 
    {IOException.class, SQLException.class})
public void riskyOperation() throws IOException {
// IOException veya SQLException olursa rollback olur
}

@Transactional(noRollbackFor = 
    IllegalArgumentException.class)
public void safeOperation() {
// IllegalArgumentException olursa rollback olmaz
}
                                                            
                                                                                            

@Transactional Parametreleri timeout

Transaction maksimum çalışma süresini (saniye cinsinden) belirler. Süre aşılırsa rollback yapılır.

Örneğin:


@Transactional(timeout = 5)
public void longRunningTask() {
    // 5 saniyeyi geçerse rollback olur
}
                                                                                
                                                                                                                

@Transactional Parametreleri readOnly

Sorgunun sadece okuma amaçlı olduğunu belirtir. Hibernate dirty check yapmaz → performans artar.

Örneğin:


@Transactional(readOnly = true)
public List findAllUsers() {
    return userRepository.findAll();
}
                                                                                                    
                                                                                                                                    

@Transactional Hangi Katmanlarda Kullanılmalı?

  • En doğru kullanım Service katmanıdır.
  • Repository zaten Spring Data JPA tarafından transaction içinde çalışır.
  • Controller'da kullanılmaz.

@Transactional Neden Önemlidir?

  • Veri bütünlüğünü sağlar.
  • Birden fazla tabloya yazma işlemi yapılırken, tutarsız veri oluşumunu engeller.
  • Özellikle para transferi, stok güncelleme, sipariş işlemleri gibi kritik operasyonlarda hayati önem taşır.

@Transactional Sık Karşılaşılan Problemler

  • Checked exception rollback yapmaz → rollbackFor ile belirtilmeli.
  • Transaction sadece public methodlarda çalışır (proxy tabanlı).
  • Aynı sınıf içindeki metod çağrılarında transaction devreye girmez (self-invocation problemi).
  • LazyInitializationException → transaction erken kapanırsa oluşabilir.

ÖZET

  • @Transactional → Transaction yönetimini sağlar.
  • Parametreler: propagation, isolation, timeout, readOnly, rollbackFor, noRollbackFor.
  • En iyi kullanım yeri: Service katmanı.
  • Mülakatta özellikle propagation ve isolation seviyeleri mutlaka sorulur.

@Transactional Örnek Full Service Kullanımı

Örneğin:


@Service
public class OrderService {

@Autowired
private OrderRepository orderRepository;

@Autowired
private PaymentRepository paymentRepository;

@Transactional(
    propagation = Propagation.REQUIRED, 
    isolation = Isolation.READ_COMMITTED)
public void placeOrder(
    Order order, 
    Payment payment) {
    orderRepository.save(order);
    paymentRepository.save(payment);

    if (payment.getAmount() <= 0) { 
        throw new RuntimeException("Ödeme hatalı!"); 
    } 
} 
    @Transactional(readOnly=true) 
    public List getAllOrders() { 
        return orderRepository.findAll(); 
    } 
}
                                                                                                                                            
                                                                                                                                                                            

Tasarım Desenleri

JPA Nedir ?

JPA, Java objeleri ve ilişkisel (relational) database arasında bilgi aktarımı için kullanılan bir standarttır. JPA bu ikisi arasında bir köprü görevi görür. JPA kullanabilmek için projeye implemente edilmesi gerekir ve bu yüzden Java dilindeki Hibernate, TopLink gibi çeşitli ORM araçları bilgiler konusunda bir devamlılık sağlamak için JPA kullanır. JPA aracılığıyla farklı ORM araçları ufak birkaç ayarlama dışında yazılan kod değiştirilmeden kullanılabilir.

Bir final class da içindekı liste final ise değişiklik yapılabilir mi.

Evet, bir final sınıf içindeki final liste değiştirilemez. Ancak listenin içeriği (elemanları) değiştirilebilir. Çünkü final anahtar kelimesi, değişkenin referansını sabitler, ancak listenin içeriği üzerinde değişiklik yapmaya izin verir.

Yani, final bir listeye yeni elemanlar ekleyebilir, mevcut elemanları kaldırabilir veya güncelleyebilirsiniz, ancak listeyi başka bir liste ile değiştiremezsiniz.

Örneğin:

public final class FinalListExample {
    private final List<String> list = new ArrayList<>();

    public void addElement(String element) {
        // Bu işlem geçerlidir,
        // çünkü listenin içeriği değiştiriliyor
        // liste referansı değil
        list.add(element);
    }

    // Bu metod derleme hatası verir, 
    // çünkü final liste referansı 
    // değiştirilmeye çalışılıyor
    public void changeList() {
        // list = new ArrayList<>(); // HATA!
    }
}

Set içerisinde bir student nesnesi var nesne id ve name barındırıyor. id leri aynı name leri farklı olan objeleri Set'e yerleştirirsek ne olur acıklayınız ?

her yeni new ile oluşturulan class ların hash code ları farklı olduğundan dolayı Set listesine yeni bir farklı obje olarak eklenir. Örnek kod ve çıktısı aşşağıdadır.

public static void main(String[] args) {
    Set<Student> set = new HashSet<Student>();
    set.add(new Student(1, "cello"));
    set.add(new Student(2, "mello"));
    set.stream().forEach(System.out::println);
}

class Student{
    private int id;
    private String name;

    public Student(int id, String name) {
        this.id = id;
        this.name = name;
    }
}

Output

main6.Student@7a81197d
main6.Student@5ca881b5

Ancak, Student sınıfında equals() ve hashCode() metodları doğru bir şekilde override edilirse, id'leri aynı olan nesneler aynı kabul edilir ve Set'e sadece bir kez eklenir. Bu durumda, id'leri aynı ancak name'leri farklı olan nesneler Set'te sadece bir kez yer alır.

Faktory Design Pattern ile Abstract Factory Design Pattern arasındaki fark nedir ?

Factory Design Pattern, bir nesne oluşturma sorumluluğunu alt sınıflara devreden bir tasarım desenidir. Bu desen, bir arayüz veya soyut sınıf aracılığıyla nesne oluşturmayı sağlar ve alt sınıflar, hangi nesnenin oluşturulacağını belirler.

Abstract Factory Design Pattern ise, ilişkili veya bağımsız nesne ailelerini oluşturmak için kullanılan bir tasarım desenidir. Bu desen, bir arayüz aracılığıyla birden fazla fabrika oluşturmayı sağlar ve her fabrika, belirli bir nesne ailesine ait nesneleri üretir.

Özetle, Factory Pattern tek bir nesne türünü oluşturmak için kullanılırken, Abstract Factory Pattern birden fazla nesne türünü ve ilişkili nesne ailelerini oluşturmak için kullanılır.