Savepoint, Transaction İçinde İsimlendirilmiş Bir Yer İmidir
Klasik bir transaction ya hep ya hiç mantığıyla çalışır: BEGIN ile COMMIT arasındaki her şey ya birlikte kaydedilir ya da topluca çöpe gider. Çoğu zaman tam da bunu istersiniz — ama bazen daha ince bir kontrol işinize yarar. Yani şöyle bir şey: "Şu değişiklik kümesini deneyeyim; ters giderse sadece o kısmı geri alayım, transaction'ın geri kalanı yaşamaya devam etsin."
İşte sqlite savepoint tam burada devreye giriyor. İsimli bir yer imi koyarsınız, biraz iş yaparsınız, sonra ya yaptığınız işi kalıcılaştırırsınız (RELEASE) ya da yer imine kadar geri sararsınız (ROLLBACK TO).
Ada'nın hesabından düşülen tutar da, Boris'in hesabına yatan tutar da yerinde kalır. Yanlışlıkla Nobody üzerinde yapılan güncelleme ise işlemin geri kalanını kaybetmeden geri alınmış olur.
Üç Temel Komut
Aslında tüm API üç ifadeden ibaret:
SAVEPOINT name— bir yer imi koyar.RELEASE SAVEPOINT name— yer iminden bu yana yapılan işleri korur ve yer imini kaldırır.ROLLBACK TO SAVEPOINT name— yer iminden bu yana olan her şeyi geri alır; yer imi yerinde kalır, böylece tekrar deneyebilirsiniz.
RELEASE ve ROLLBACK TO sonrasındaki SAVEPOINT kelimesi isteğe bağlıdır — yani RELEASE risky ve ROLLBACK TO risky da pekâlâ çalışır.
adım 2 denemesi satırı, son veritabanı açısından bakıldığında hiçbir zaman var olmamış gibi davranır. Geri kalan her şey kalıcı olur.
Dış Transaction Olmadan Savepoint Kullanımı
Burada küçük bir incelik var: BEGIN yazmadan da doğrudan SAVEPOINT açabilirsiniz. SQLite arka planda sizin için bir transaction başlatır ve en dıştaki savepoint, transaction'ın kendisi rolünü üstlenir. O savepoint üzerinde RELEASE çağırmak commit anlamına gelir; ROLLBACK TO ise commit etmeden geri sarar.
İşte savepoint'lerin neden bazen "isimli transaction" olarak anıldığını gösteriyor. Ama gerçek kodda bu iki stili karıştırmak kafa karıştırıcı olur — birini seçin. Çoğu kişi dış sınır için açıkça BEGIN ... COMMIT kullanıp, savepoint'leri yalnızca içerideki kısmi geri alma noktaları için tercih ediyor.
SQLite İç İçe Savepoint Kullanımı
Savepoint'ler yığın gibi çalışır. Birinin içinde başka bir savepoint tanımlayabilir ve dıştakine dokunmadan içtekini geri alabilirsiniz:
Son durumdaki kayıtlar: a, b, d. inner noktasına dönmek c kaydını sildi, ama inner öncesinde yapılan işi (yani b eklemesini) olduğu gibi bıraktı; transaction da kaldığı yerden devam etti.
Dış (outer) bir savepoint'e geri dönmek, iç seviyelerde yapılan her şeyi de çöpe atar — o ismin üzerindeki tüm yığın tek seferde çözülür:
b ve c artık yok. ROLLBACK TO outer, outer belirlendikten sonra olan her şeyi geri alıyor; buna inner ve c insert'i de dahil.
SQLite SAVEPOINT ne işe yarar?
Klasik kullanım senaryosu şu: bir batch işliyorsunuz ve tek bir kaydın hatalı olması yüzünden tüm batch'in çöpe gitmesini istemiyorsunuz. Her kaydı bir savepoint içine sarın; hata olursa o savepoint'e geri dönüp bir sonrakine geçin:
Gerçek uygulama kodunda hatalı INSERT bir hata fırlatır, uygulama bunu yakalar, ROLLBACK TO çalıştırır ve yoluna devam eder. Sağlam iki satır kaydedilir; bozuk satır ise tüm grubu zehirlemez.
Bu desen aynı zamanda ORM'lerin ve migration araçlarının iç içe transaction'ları nasıl uyguladığının da yanıtıdır — aslında BEGIN bloklarını iç içe açmazlar (zaten SQLite buna izin vermez), iç içe çağrıları savepoint'lere eşlerler.
Dikkat Edilmesi Gereken Birkaç Nokta
Savepoint konusuna yeni başlayanların sıkça takıldığı birkaç ayrıntı:
COMMITher zaman transaction'ın tamamını işler. Kaç tane açık savepoint olduğu fark etmez —COMMIT(veya takma adıEND) en dıştaki transaction'ı kapatır.RELEASE'i kısmi bir commit gibi düşünmeyin; çevreleyen transaction commit edilene kadar hiçbir şey kalıcı değildir.ROLLBACK(yanındaTOolmadan) her şeyi iptal eder. Transaction'ı sonlandırır ve tüm açık savepoint'leri çöpe atar. Transaction'ı hayatta tutmak istiyorsanızROLLBACK TO adkullanın.- Bir savepoint, release edilene veya üzerinden geri alınana kadar açık kalır.
RELEASEetmeyi unutmak veri kaybına yol açmaz; yer imi sadece transaction bitene kadar orada öylece bekler. - İsimlerin benzersiz olması gerekmiyor.
SAVEPOINT skomutunu iki kez verirseniz,ROLLBACK TO sen yakın olanı bulur. Özyinelemede işe yarar; ama yanlışlıkla yapılırsa kafa karıştırır.
Sırada: View'lar
Savepoint'ler size yazma işlemleri üzerinde daha ince bir kontrol sağlıyor. Bir sonraki adım ise okuma tarafını şekillendirmek — bir sorguyu adlandırılmış, tekrar kullanılabilir bir nesne olarak kaydedip ona tablo gibi SELECT çekmek. İşte buna view deniyor ve bir sonraki konumuz bu.
Sıkça Sorulan Sorular
SQLite'ta savepoint nedir?
Savepoint, bir transaction'ın içine koyduğunuz isimli bir işarettir. İşler ters giderse ROLLBACK TO isim ile o noktadan sonra yapılan her şeyi geri alabilir, işiniz bittiyse RELEASE ile değişiklikleri koruyup işareti kaldırabilirsiniz. Yani transaction'ınızı küçük, kurtarılabilir parçalara bölmüş olursunuz.
Savepoint ile transaction arasındaki fark nedir?
Transaction BEGIN ile başlar, COMMIT veya ROLLBACK ile biter. Savepoint ise transaction'ın içinde SAVEPOINT isim ile oluşturulur ve size kısmi bir geri alma noktası verir. Bir savepoint'e geri dönmek dıştaki transaction'ı sonlandırmaz; çalışmaya devam edip daha sonra commit edebilirsiniz.
SQLite savepoint'leri iç içe kullanılabilir mi?
Evet. Farklı isimlerle savepoint'leri üst üste yığabilirsiniz; ROLLBACK TO disSavepoint o seviyeye kadar olan her şeyi, içerdeki tüm savepoint'ler dahil geri alır. İsimlerin benzersiz olma zorunluluğu da yok — SQLite aynı isim varsa en yakın olanı kullanır, yani klasik stack mantığı işler.