CRUD uygulamalarında yinelenen kayıtları önlemek birkaç katman gerektirir: veritabanı benzersiz kısıtları, idempotent anahtarlar ve çift gönderimleri engelleyen kullanıcı arayüzü durumları.

Yinelenen kayıt, uygulamanızın aynı şeyi iki kez kaydetmesi durumudur. Bu, aynı checkout için iki sipariş, aynı detaylara sahip iki destek bileti veya aynı kayıt akışından oluşturulmuş iki hesap olabilir. CRUD uygulamalarında, tek tek satırlar normal görünebilir ama veriye bütün olarak bakınca yanlış olurlar.
Çoğu yinelenen kayıt normal davranışla başlar. Birisi Sayfa yavaş hissedildiği için Create düğmesine iki kez tıklar. Mobilde çift dokunma kolayca fark edilmez. Düğme hâlâ aktif görünüyorsa ve bir şeyin olup olmadığı açık değilse dikkatli kullanıcılar bile tekrar dener.
Sonra ağ ve sunucular devreye girer: istek zaman aşımına uğrayıp otomatik olarak yeniden denenebilir. Bir istemci kütüphanesi, ilk denemenin başarısız olduğunu düşünerek bir POST'u tekrarlayabilir. İlk istek başarılı olmuş ama yanıt kaybolmuş olabilir; kullanıcı tekrar dener ve ikinci bir kopya oluşur.
Bunu tek bir katmanda çözemezsiniz çünkü her katman hikayenin sadece bir kısmını görür. UI kazara çift gönderimleri azaltabilir ama kötü bağlantılardan gelen yeniden denemeleri durduramaz. Sunucu tekrarları algılayabilir ama “bu aynı create tekrar”ı güvenilir bir şekilde tanıması gerekir. Veritabanı kuralları uygulayabilir, ama “aynı şey”in ne anlama geldiğini tanımlarsanız işe yarar.
Amaç basit: aynı istek iki kez gönderilse bile create işlemini güvenli hale getirmek. İkinci deneme no-op olmalı, temiz bir “zaten oluşturulmuş” yanıtı döndürmeli veya kontrollü bir çakışma olmalı, ikinci bir satır değil.
Birçok ekip yinelenenleri veritabanı sorunu olarak görür. Pratikte, yinelenenler genellikle daha erken başlar; aynı create eylemi birden çok kez tetiklenir.
Kullanıcı Create'e tıklar ve hiçbir şey olmuyormuş gibi görünür, bu yüzden tekrar tıklar. Ya da Enter'a basar, hemen ardından düğmeye tıklar. Mobilde iki hızlı dokunuş, dokunma ve tıklama olaylarının çakışması veya bir jestin iki kez algılanması görülebilir.
Kullanıcı sadece bir kez gönderse bile ağ isteği yine de tekrarlanabilir. Bir zaman aşımı yeniden denemeye yol açabilir. Çevrimdışı bir uygulama bir “Kaydet”i kuyruğa alıp yeniden bağlanınca yeniden gönderebilir. Bazı HTTP kütüphaneleri belirli hatalarda otomatik yeniden deneme yapar ve tek farkı çoğaltılmış satırları görmek olur.
Sunucular kasıtlı olarak işi tekrarlar. İş kuyrukları başarısız işleri yeniden dener. Webhook sağlayıcıları, özellikle uç noktanız yavaşsa veya 2xx olmayan bir durum döndürürse aynı olayı birden çok kez gönderebilir. Create mantığınız bu olaylarla tetikleniyorsa, yinelenmeler olacağını varsayın.
Eşzamanlılık en sinsisi olan yinelenmeleri yaratır. İki sekme aynı formu milisaniyeler içinde gönderir. Sunucunuz "var mı?" kontrolü yapıp sonra insert ediyorsa, her iki istek de insert olmadan önce kontrolleri geçebilir.
İstemciyi, ağı ve sunucuyu tekrar kaynakları olarak düşünün. Hepsinde savunmalar olmalı.
Tek güvenilir yer istiyorsanız kuralı veritabanına koyun. UI düzeltmeleri ve sunucu kontrolleri yardımcı olur, ama yeniden denemeler, gecikmeler veya aynı anda iki kullanıcı olduğunda başarısız olabilirler. Bir veritabanı benzersiz kısıtı nihai otoritedir.
Gerçek dünyadaki benzersizlik kuralını seçerek başlayın; insanların kayıt hakkında nasıl düşündüğünü eşleştiren bir kural olmalı. Yaygın örnekler:
Tam adı gibi benzersiz gibi görünen ama gerçekte olmayan alanlara dikkat edin.
Kuralı belirledikten sonra benzersiz kısıtlama (veya benzersiz indeks) ile uygulayın. Bu, iki istek aynı anda gelse bile ikinci insert'i engeller.
Kısıt tetiklendiğinde kullanıcının ne deneyimleyeceğine karar verin. Eğer duplicate her zaman yanlışsa, bunu net bir mesajla engelleyin ("Bu e-posta zaten kullanılıyor"). Yeniden denemeler yaygınsa ve kayıt zaten varsa, yeniden denemeyi başarı olarak ele almak ve mevcut kaydı döndürmek genellikle daha iyidir ("Siparişiniz zaten oluşturulmuş").
Eğer create gerçekten "oluştur ya da yeniden kullan" ise, upsert en temiz desen olabilir. Örnek: "e-posta ile müşteri oluştur" ya yeni bir satır ekler ya da mevcut olanı döndürür. Bu sadece iş anlamıyla uyuyorsa kullanılmalı. Aynı anahtar için hafifçe farklı payload'lar gelebiliyorsa hangi alanların güncellenebileceğine hangi alanların değişmemesi gerektiğine karar verin.
Benzersiz kısıtlar idempotent anahtarların veya iyi UI durumlarının yerini almaz, ama diğer her şeyin dayanabileceği sert bir durma noktası sunarlar.
Idempotent anahtar, bir kullanıcı niyetini temsil eden benzersiz bir tokendir; örneğin "bu siparişi bir kere oluştur". Aynı istek tekrar gönderilirse (çift tıklama, ağ yeniden denemesi, mobil devam etme), sunucu bunu yeni bir create değil, bir yeniden deneme olarak ele alır.
Bu, istemcinin ilk denemenin başarılı olup olmadığını bilemediği durumlarda create uç noktalarını güvenli hale getirmek için en pratik araçlardan biridir.
Çoğunlukla kopya olması maliyetli veya kafa karıştırıcı olan uç noktalar bu yöntemden fayda görür: siparişler, faturalar, ödemeler, davetler, abonelikler ve e-posta veya webhook tetikleyen formlar.
Bir yeniden denemede sunucu ilk başarılı denemenin orijinal sonucunu, aynı oluşturulan kayıt ID'si ve durum kodu dahil, döndürmelidir. Bunu yapmak için (kullanıcı veya hesap) + endpoint + idempotent anahtar ile anahtarlanan küçük bir idempotency kaydı saklayın. Hem sonucu (kayıt ID'si, yanıt gövdesi) hem de "devam ediyor" durumunu saklayın ki iki neredeyse eşzamanlı istek iki satır oluşturmasın.
Idempotency kayıtlarını gerçek yeniden denemeleri kapsayacak kadar uzun tutun. Yaygın bir taban çizgisi 24 saattir. Ödemeler için birçok ekip 48–72 saat tutar. Bir TTL depolamayı sınırlı tutar ve yeniden denemenin ne kadar süreyle olası olduğunu yansıtır.
Eğer Koder.ai gibi bir sohbet destekli üreticiyle API'ler oluşturuyorsanız, idempotentliği yine de açık hale getirin: istemciden bir anahtar kabul edin (başlık veya alan) ve sunucuda "aynı anahtar, aynı sonuç" ilkesini uygulayın.
Idempotentlik bir create isteğini tekrar güvenli yapar. İstemci zaman aşımı nedeniyle yeniden denese (veya kullanıcı iki kez tıklasa), sunucu aynı sonucu döndürür yerine ikinci bir satır oluşturmaz.
Idempotency-Key) iyi çalışır, ama JSON gövdesinde göndermek de işe yarar.Önemli nokta, "kontrol + sakla" işleminin eşzamanlılık altında güvenli olmasıdır. Pratikte idempotency kaydını (scope, key) üzerinde benzersiz bir kısıtlama ile saklar ve çakışmaları yeniden kullanma sinyali olarak ele alırsınız.
if idempotency_record exists for (user_id, key):
return saved_response
else:
begin transaction
create the row
save response under (user_id, key)
commit
return response
Örnek: bir müşteri "Fatura oluştur"a basar, uygulama abc123 anahtarını gönderir ve sunucu inv_1007 faturasını oluşturur. Telefon bağlantısı kopup yeniden denerse sunucu inv_1007 yanıtını döndürür, inv_1008 değil.
Test ederken sadece "çift tıklama" ile yetinmeyin. İstemcinin zaman aşımına uğrayıp sunucunun yine de isteği tamamladığı bir senaryoyu simüle edip aynı anahtarla yeniden deneyin.
Sunucu tarafı savunmaları önemli ama birçok yinelenen kayıt insanın aynı şeyi iki kere yapmasıyla başlar. İyi bir UI güvenli yolu açıkça gösterir.
Gönderme işlemi başladığında gönder butonunu devre dışı bırakın. Bunu ilk tıklamada yapın; doğrulamadan veya isteğin başlamasından sonra değil. Form birden fazla kontrolle gönderilebiliyorsa (düğme ve Enter), yalnızca bir düğmeyi kilitlemek yerine tüm form durumunu kilitleyin.
Çalışıp çalışmadığını cevaplayan net bir ilerleme durumu gösterin. Basit bir "Kaydediliyor..." etiketi veya bir spinner yeterlidir. Düzeni sabit tutun ki düğme yer değiştirip ikinci tıklamayı teşvik etmesin.
Çok küçük bir kural seti çoğu çift gönderimi önler: submit handler başında bir isSubmitting bayrağı ayarlayın, bu doğruyken yeni gönderimleri yok sayın (hem tıklama hem Enter için) ve gerçek yanıt gelene kadar bayrağı temizlemeyin.
Yavaş yanıtlar birçok uygulamanın takıldığı yerdir. Düğmeyi sabit bir zamanlayıcıyla (örneğin 2 saniye sonra) yeniden etkinleştirirseniz, kullanıcı ilk istek hâlâ uçtayken tekrar gönderebilir. Yalnızca deneme tamamlandığında yeniden etkinleştirin.
Başarının ardından yeniden gönderimi zorlaştırın. Yeni kayıt sayfasına yönlendirin veya oluşturulan kaydı gösteren net bir başarı durumu gösterin. Aynı dolu formu ekranda bırakıp düğmeyi açık bırakmaktan kaçının.
İnatçı yinelenen hatalar günlük "garip ama yaygın" davranışlardan gelir: iki sekme, yenileme veya telefonun bağlantıyı kaybetmesi.
Önce benzersizliği doğru şekilde kapsayın. "Benzersiz" nadiren "tüm veritabanında benzersiz" demektir. Genellikle bir kullanıcı başına, bir workspace başına veya tenant başına benzersizdir. Harici bir sistemle senkronize ediyorsanız, harici kaynak + dış ID başına benzersizlik gerekebilir. Güvenli bir yaklaşım ne demek istediğinizi açıkça yazmaktır (örneğin "Bir tenant için bir fatura numarası yıl başına bir tane"), sonra bunu uygulamak.
Çoklu sekme davranışı klasik bir tuzaktır. UI yükleme durumları tek bir sekmede yardımcı olur ama sekmeler arasında hiçbir şey yapmaz. Bu yüzden sunucu tarafı savunmalar hâlâ sağlam olmalı.
Geri tuşu ve yenileme kazara yeniden gönderimleri tetikleyebilir. Başarılı bir create sonrası kullanıcılar çoğunlukla yenileme yapıp kontrol etmek ister veya Back ile aynı düzenlenebilir formu tekrar submit edebilir. Oluşturulan bir görünüm tercih edin, orijinal form yerine, ve sunucunun güvenli tekrarları ele almasını sağlayın.
Mobil kesintiler ek zorluk getirir: arka plana alma, değişken ağlar ve otomatik yeniden denemeler. Bir istek başarılı olabilir ama uygulama yanıtı hiç almayabilir; bu yüzden uygulama yeniden başladıktan sonra tekrar deneyebilir.
En yaygın başarısızlık modu UI'yi tek koruma olarak görmektir. Devre dışı bırakılmış bir düğme ve spinner yardımcı olur ama yenilemeler, mobil ağ aksaklıkları, ikinci sekme veya istemci hatalarını kapsamaz. Sunucu ve veritabanı yine de "bu create zaten oldu" diyebilmelidir.
Diğer bir tuzak yanlış alanı benzersiz kabul etmektir. Eğer benzersiz olmayan bir alana (soyadı, yuvarlanmış zaman damgası, serbest başlık) benzersiz kısıtlama koyarsanız geçerli kayıtları engellersiniz. Bunun yerine gerçek bir tanımlayıcı (ör. harici sağlayıcı ID'si) veya kapsamlı bir kural (kullanıcı başına, gün başına veya üst kayıt başına benzersiz) kullanın.
Idempotent anahtarlar da kötü uygulanması kolay bir konudur. İstemci her yeniden denemede yeni bir anahtar üretirse, her seferinde yeni bir create elde edersiniz. Aynı anahtarı ilk tıklamadan tüm yeniden denemelere kadar koruyun.
Ayrıca yeniden denemelerde ne döndürdüğünüze dikkat edin. İlk istek kaydı oluşturduysa, bir yeniden deneme aynı sonucu (ya da en azından aynı kayıt ID'sini) döndürmeli, kullanıcıyı tekrar denemeye iten belirsiz bir hatayla karşılaşmamalıdır.
Bir benzersiz kısıtlama duplicate'ı engellediyse, bunu "Bir şeyler ters gitti" arkasına saklamayın. Ne olduğunu açıkça söyleyin: "Bu fatura numarası zaten mevcut. Orijinali koruduk, ikinciyi oluşturmadık."
Yayınlamadan önce duplicate create yolları için özel bir kontrol yapın. En iyi sonuçlar, kaçırılmış bir tıklama, yeniden deneme veya yavaş ağ durumunda iki satır oluşturamayacak şekilde bir dizi savunma üst üste koymaktan gelir.
Üç şeyi doğrulayın:
Pratik bir kontrol: formu açın, hızlıca iki kez submit tıklayın, ardından submit sırasında yenileyin ve tekrar deneyin. Eğer iki kayıt oluşturabiliyorsanız gerçek kullanıcılar da oluşturur.
Küçük bir faturalama uygulaması hayal edin. Kullanıcı yeni bir fatura doldurur ve Create'e dokunur. Ağ yavaştır, ekran hemen değişmez ve tekrar Create'e dokunur.
Sadece UI koruması varsa düğmeyi devre dışı bırakıp spinner gösterebilirsiniz. Bu yardımcı olur ama yeterli değildir. Bazı cihazlarda çift dokunma hâlâ sızabilir, bir zaman aşımı sonrası yeniden deneme olabilir veya kullanıcı iki sekmeden submit edebilir.
Sadece veritabanı benzersiz kısıtınız olsa, tam kopyaları durdurursunuz ama deneyim zor olabilir. İlk istek başarılı olur, ikinci kısıta takılır ve kullanıcı bir hata görür; oysa fatura zaten oluşturulmuştur.
Temiz sonuç idempotentlik + benzersiz kısıtların birleşimidir:
İkinci tıklama sonrası basit bir UI mesajı: "Fatura oluşturuldu - biz duplicate gönderimi yok saydık ve ilk isteğinizi koruduk." şeklinde olabilir.
Temeli kurduktan sonra sıradaki kazançlar görünürlük, temizlik ve tutarlılıkla ilgilidir.
Create yollarının etrafına hafif loglama ekleyin ki gerçek kullanıcı eylemi ile yeniden denemeyi ayırt edebilin. Idempotency anahtarını, ilgili benzersiz alanları ve sonucu (oluşturuldu vs var olan döndürüldü vs reddedildi) loglayın. Başlamak için ağır araçlara gerek yok.
Eğer zaten duplicate kayıtlar varsa, net bir kural ve denetim izi ile temizleyin. Örneğin en eski kaydı “kazanan” olarak tutun, ilişkili satırları (ödemeler, satır kalemleri) yeniden ilişkilendirin ve diğerlerini silmek yerine birleştirilmiş/merged olarak işaretleyin. Bu destek ve raporlama işini kolaylaştırır.
Benzersizlik ve idempotency kurallarınızı bir yerde yazılı tutun: ne benzersizdir ve hangi kapsamda, idempotency anahtarları ne kadar yaşar, hatalar nasıl görünür ve UI yeniden denemelerde ne yapmalı. Bu yeni uç noktaların güvenlik raylarını atlamasını önler.
Eğer CRUD ekranlarını hızlıca Koder.ai (koder.ai) ile oluşturuyorsanız, bu davranışları varsayılan şablonlarınızın parçası yapmak değerli olur: şemada benzersiz kısıtlar, API'de idempotent create uç noktaları ve UI'de net yükleme durumları. Böylece hız, dağınık veri pahasına gelmez.
Bir CRUD uygulamasında yinelenen kayıt, aynı gerçek dünya varlığının iki kez saklanmasıdır; örneğin tek bir ödeme için iki sipariş veya aynı sorun için iki destek bileti. Genellikle aynı “create” işleminin kullanıcı tarafından iki kez tetiklenmesi, yeniden denemeler veya eşzamanlı istekler yüzünden oluşur.
Kullanıcı sadece bir kez tıklasa bile yinelenen yaratılabilir çünkü çift dokunma, Enter tuşuna basmak ve düğmeye tıklamak gibi davranışlar birden fazla create isteği üretebilir. Ayrıca istemci, ağ veya sunucu zaman aşımından sonra isteği yeniden deneyebilir; bu yüzden sunucu her zaman “POST bir kez yapıldı” varsayamaz.
Tek başına yeterli değil. Düğmeyi devre dışı bırakmak ve “Kaydediliyor...” göstermek kazara çift gönderimleri azaltır ama kötü ağ koşulları, sayfa yenilemeleri, birden çok sekme, arka plan işçileri veya webhook yeniden teslimatlarını engelleyemez. Sunucu ve veritabanı savunmaları da gerekir.
Benzersiz bir kısıtlama, iki istek aynı anda gelse bile iki satırın eklenmesini engelleyen son savunma hattıdır. Gerçek dünyadaki benzersizlik kuralını (çoğunlukla tenant veya workspace gibi bir kapsamla) tanımlayın ve bunu doğrudan veritabanında uygulayın.
İkisi de gerekli olabilir. Benzersiz kısıtlar alan bazlı tekrarları engeller (ör. fatura numarası), idempotent anahtarlar ise belirli bir create denemesinin tekrar güvenli olmasını sağlar (aynı anahtar aynı sonucu döner). İkisini birlikte kullanmak güvenlik ve daha iyi kullanıcı deneyimi sağlar.
Her kullanıcı niyeti için (örneğin “Fatura oluştur” butonuna basıldığında) bir anahtar oluşturun, bu anahtarı aynı niyet için yapılacak tüm yeniden denemelerde yeniden kullanın ve isteğe her seferinde gönderin. Anahtar, zaman aşımı veya uygulama tekrar açılmaları boyunca sabit kalmalı; farklı bir create için yeniden kullanılmamalıdır.
Sunucuda, kapsam (kullanıcı veya hesap), endpoint ve idempotent anahtar ile anahtara göre bir idempotency kaydı saklayın ve ilk başarılı isteğe verdiğiniz yanıtı kaydedin. Aynı anahtar tekrar gelirse yeni bir satır oluşturmayın; ilk isteğe verdiğiniz kaydedilmiş yanıtı (aynı kayıt ID'si dahil) döndürün.
Güvenli bir "kontrol + sakla" yaklaşımı kullanın; pratikte idempotency kaydı üzerinde (scope, key) için benzersiz bir kısıtlama uygulayıp çakışmaları var olan sonucu yeniden kullanma sinyali olarak ele alırsınız. Bu, iki neredeyse eşzamanlı isteğin ikisinin de “ilk” olduğunu iddia etmesini engeller.
Gerçekçi yeniden denemeleri karşılayacak kadar uzun tutun; yaygın bir varsayılan 24 saattir. Ödemeler gibi akışlar için 48–72 saat tutulur. Bir TTL ekleyin ki depolama kontrolsüz büyümesin ve anahtarların ne kadar süreyle yeniden denenebileceğiyle uyumlu olsun.
Eğer niyetin aynı olduğu açıkça belliyse, yinelenen create işlemini başarılı bir yeniden deneme olarak değerlendirin ve orijinal kaydı (aynı ID ile) döndürün. Eğer gerçekten benzersiz olması gereken bir şeyse (ör. e-posta), kullanıcıya ne olduğu açık bir şekilde söyleyen bir çakışma mesajı verin: “Bu e-posta zaten kullanılıyor; orijinalini koruduk.”