Flush ve SQL Sırası — save() Satırında Neden Hiçbir Şey Olmuyor?
Önce şunu oku: ID Üretimi ve Batch Insert — 200 Satır Kaç Gidiş Dönüş?
30 saniyede özet
save() dediğinde veritabanına hemen bir şey gitmez; değişiklik bir listeye yazılır. Liste sonra toplu gönderilir, üstelik senin sıranla değil: önce eklemeler, en son silmeler. Hatalar da o an ortaya çıkar.
Kod önce eski hesabı siliyor, sonra aynı e-postayla yenisini ekliyordu. Veritabanı unique kısıt hatası verdi. Oysa kodun sırası tertemizdi.
-
Bayt: Önce eski hesabı sildim, sonra aynı e-postayla yenisini ekledim. Sıra kusursuz.
-
Sen: Ve?
-
Bayt: Veritabanı aynı e-posta iki kez var diye bağırdı!
-
Bayt: Kodu yazdığın sıra ile SQL'in gittiği sıra aynı mı? Önce tahmin et.
save() bir not, SQL değil
save() ve persist() değişikliği persistence context’teki bir kuyruğa koyar. Veritabanına giden SQL, flushPersistence context'teki bekleyen değişiklikleri SQL olarak veritabanına göndermek. Commit değildir: transaction açık kalır ve geri alınabilir.Sözlükte gör → anında çalışır.
Varsayılan FlushModeFlush'ın ne zaman otomatik yapılacağı. AUTO (varsayılan) commit'ten ve etkilenecek sorgulardan önce flush eder; COMMIT yalnızca commit'te.Sözlükte gör → AUTO, commit’ten önce ve sonucu etkilenecek bir sorgudan önce flush eder. Böylece kod, aynı transaction’da kendi yazdığını görür. Flush commit değildir: transaction açık kalır ve geri alınabilir.
Kafam karıştı, daha basit anlat
save() postaya mektup bırakmaktır, mektubun yola çıkması değil. Mektuplar flush anında toplu hâlde yola çıkar.
Sequence ile id alan bir entity için orders.save(order) çağrıldı. O satırda veritabanına ne gider?
flush ile commit arasındaki fark nedir?
Varsayılan FlushMode AUTO'da, persist ettiğin bir siparişin ardından aynı transaction'da JPQL ile sipariş sayısını sorguluyorsun. Sonuç yeni siparişi içerir mi?
Zarflar hangi sırayla gider?
Aynı transaction'da önce accounts.delete(eski), sonra accounts.save(new Account(aynı e-posta)). Commit'te hangi SQL önce gider? Cevabı göster
INSERT. Flush, işlemleri koddaki sırayla değil türüne göre çalıştırır: önce insert’ler, en son delete’ler. Yeni satır eklenirken eski satır hâlâ duruyordur ve unique kısıt patlar.
Adım adım oku
- Kod önce eski hesabı siliyor, sonra aynı e-postayla yenisini ekliyor.
- İkisi de flush anına kadar bekler; flush'ta Hibernate SQL'leri kendi düzenine göre dizer.
- INSERT'ler DELETE'lerden önce gider; yeni hesap eklenirken eskisi hâlâ durduğu için unique kısıtı patlar.
- Silmeden sonra açıkça flush() çağırmak DELETE'i hemen gönderir; INSERT ondan sonra gider.
Bu sırayı action queueHibernate'in flush'ta çalıştıracağı işlemleri tuttuğu kuyruk. İşlemleri koddaki sırayla değil türüne göre çalıştırır: insert, update, koleksiyonlar, en son delete.Sözlükte gör → belirler. Sıranın önemli olduğu yerde araya bir flush() koyarsın; çoğu zaman daha iyisi, silip eklemek yerine satırı güncellemektir.
Kafam karıştı, daha basit anlat
Postacı mektupları senin yazdığın sırayla değil, türüne göre dağıtır: önce eklemeler, en son silmeler. Sıra önemliyse araya kendin bir flush koy.
Kullanıcı e-postasını değiştirmek için eski hesabı silip aynı e-postayla yenisini oluşturan kod unique kısıt hatası veriyor. Hatalı satır hangisi?
FlushMode AUTO'da her işlemi, flush'ı tetikleyip tetiklemediğine göre ayır.
Kendin gör
SQL ne zaman gidiyor?
Tohum 739720Oynat ya da adımla.
Şu an ne oldu?
Aynı e-postayla sil ve ekle
save() ve persist() SQL göndermez; değişikliği kuyruğa koyar. SQL, flush anında ve Hibernate'in seçtiği sırayla gider.
Görevler0/3
Önce silip sonra eklediğin hâlde unique kısıtı patlataçık
İpucu
Varsayılan ayarlar yeter.
Aynı transaction'da persist ettiğin siparişi sayımda kaçıraçık
İpucu
FlushMode'a bak.
Kısıt hatasını catch bloğunda yakalaaçık
İpucu
Hatanın hangi satırda fırlayacağını belirle.
Olay günlüğü (0)
Henüz olay yok. Oynat veya adımla.
- Varsayılanla oynat. Sil ve ekle: INSERT önce gitti, unique kısıt patladı.
- “Doğru yerde flush et”i aç. DELETE önce gitti.
- Senaryoyu “try/catch içinde save” yap, flush’ı kapat. Hata commit’te fırladı, catch’e hiç girilmedi.
- Flush’ı aç. saveAndFlush, hatayı catch bloğunun içine taşıdı.
- “persist, sonra JPQL sayım” seç ve FlushMode’u COMMIT yap. Sayım yeni siparişi görmedi.
try { orders.save(order); } catch (DataIntegrityViolationException e) { … } yazdın, ama duplicate sipariş numarasında catch bloğuna hiç girilmiyor ve istemci 500 alıyor. Neden?
Tuzaklar
Her save’ten sonra flush. Sorunları görünür kılar ama batching’i öldürür ve her flush’ta dirty checking çalıştırır. Flush’ı yalnızca sıranın ya da hata yerinin önemli olduğu yerde kullan.
readOnly metotta yazmak. Spring, readOnly transaction’da Hibernate’in flush’ını kapatır. Değişiklik hatasız kaybolur.
Döngüde sorgu. Her JPQL sorgusundan önce otomatik flush çalışır. Büyüyen bir persistence context’te bu, her iterasyonu biraz daha pahalı yapar.
Kafam karıştı, daha basit anlat
Her mektuptan sonra postaneye koşma. Flush’ı yalnızca sıranın gerçekten önemli olduğu yerde elle çağır.
@Transactional(readOnly = true) bir metotta entity'nin bir alanını değiştirdin. Spring + Hibernate'te ne olur?
Aşağıdaki örnek bir bankanın kayıtlı alıcı ve kredi sözleşmesi servislerinden. Flush yalnızca gereken üç yerde, bilinçli kullanılıyor: sıranın önemli olduğu yerde, hatanın belirli bir satırda yakalanması gereken yerde ve döngüdeki gereksiz otomatik flush’ı kapatmak için.
Derinleş · Kayıtlı alıcılar ve kredi sözleşmeleri: flush'ı bilerek kullanmak 6 dosya · ~106 satır · ilk okumada atlayabilirsin
Kendini sına
save() çağrısı SQL'i hemen veritabanına gönderir.
Hibernate flush'ta işlemleri hangi sırayla çalıştırır?
Aklında kalacak üç şey
- 1 save ve persist SQL göndermez. Değişiklikler flush anında gider: commit'te, etkilenecek bir sorgudan önce ya da açık bir flush çağrısında.
- 2 Flush'ta Hibernate işlemleri türüne göre sıralar: önce eklemeler, sonra güncellemeler, en son silmeler. Aynı benzersiz değeri silip yeniden eklemek için aradaki flush'ı kendin yaparsın.
- 3 Kısıt hatası SQL'in çalıştığı anda çıkar. save'i saran bir try/catch onu göremez; belli bir satırda yakalamak için saveAndFlush gerekir.
5 kart sonraki derste seni bekliyor
Bu dersin üstüne kurulanlar
Bunlar bu dersi temel alıyor; hazır olduğunda devam edebilirsin.
- Hibernate ve JPAToplu UPDATE — Veritabanı Değişti, Nesnen Neden Haberi Yok?Tek sorguyla bin hesabı DORMANT yaptın. Az önce yüklediğin hesap 7 hâlâ ACTIVE diyor. Kim yalan söylüyor?Derse git
- Hibernate ve JPAjoin fetch ve Sayfalama — 10 Sipariş İçin Bütün TabloSayfada 10 sipariş var, SQL'de LIMIT yok. Veritabanından kaç satır geldi?Derse git
- Hibernate ve JPAKalıtım Stratejileri — Üç Ödeme Türü, Kaç Tablo?Kart, havale ve fatura ödemesi: üçü de Payment. Veritabanında kaç tablo olmalı?Derse git
- Hibernate ve JPAEnum Eşleme — Bloklu Kart Neden Bir Gün Dondurulmuş Göründü?Kodda yalnızca yeni bir kart durumu ekledin. Ertesi sabah bloklu kartlar dondurulmuş görünüyor. Veritabanına kimse dokunmadı. Ne oldu?Derse git