Bir web uygulamasında yarış koşulları nasıl önlenir?


31

Alice ve Bob'un ikisinin de ürün listelerini düzenlediği bir e-ticaret sitesini düşünün. Alice açıklamaları geliştirirken, Bob fiyatları da güncelliyor. Acme Wonder Widget'ı aynı anda düzenlemeye başlarlar. Bob ilk önce biter ve ürünü yeni fiyattan kurtarır. Alice'in açıklamasını güncellemesi biraz daha uzun sürüyor ve bitirdiğinde ürünü yeni açıklamasıyla birlikte kaydediyor. Maalesef, aynı zamanda, fiyatı amaçlanmayan eski fiyatın üzerine yazıyor.

Deneyimlerime göre, bu sorunlar web uygulamalarında oldukça yaygın. Bazı yazılımlar (örneğin, wiki yazılımı) buna karşı koruma sağlar - genellikle ikinci kaydetme "düzenleme yapılırken sayfa güncellendi" ile başarısız olur. Ancak çoğu web sitesinde bu koruma yoktur.

Denetleyici yöntemlerinin kendi başlarına iplik güvenli olduğuna dikkat etmek önemlidir. Genellikle, eğer Alice ve Bob aynı anda tasarruf etmeye çalışırlarsa, yolsuzluğa yol açmayacakları anlamında onları güvenli kılan veritabanı işlemlerini kullanırlar. Yarış durumu, Alice veya Bob’un tarayıcılarında eski verilerden kaynaklanıyor.

Bu tür yarış koşullarını nasıl önleyebiliriz? Özellikle bilmek istiyorum:

  • Hangi teknikler kullanılabilir? örneğin son değişimin zamanının izlenmesi. Her birinin avantajları ve dezavantajları nelerdir.
  • Yardımcı bir kullanıcı deneyimi nedir?
  • Bu koruma hangi çerçevelerde inşa edilmiştir?

Daha önce cevabı verdiniz: nesnelerin değişme tarihini takip ederek ve diğer değişikliklerin güncellemeye çalıştığı verilerin yaşıyla karşılaştırarak. Başka bir şey bilmek ister misiniz, örneğin verimli bir şekilde nasıl yapmalısınız?
Kilian Foth

@KilianFoth - Özellikle bilmek
istediklerim

1
Sorunuz hiçbir şekilde web uygulamalarına özel değildir, masaüstü uygulamalarında da aynı problem olabilir. Tipik çözüm stratejileri burada açıklanmaktadır: stackoverflow.com/questions/129329/…
Doc Brown

2
Bilginize, sorunuzda bahsettiğiniz kilitleme şekli " iyimser eşzamanlılık kontrolü " olarak bilinir
TehShrike

Yanıtlar:


17

"Yazdıklarınızı okumanız" gerekir; bu, bir değişiklik yazmadan önce, kaydı tekrar okumanız ve en son okuduğunuzdan bu yana yapılan değişiklik olup olmadığını kontrol etmeniz gerekir. Bu tarla-tarla (ince taneli) veya zaman damgasına (kaba taneli) dayalı olarak yapabilirsiniz. Bu kontrolü yaparken kayıtta özel bir kilit gerekir. Herhangi bir değişiklik yapılmazsa, değişikliklerinizi yazıp kilidi açabilirsiniz. Bu arada kayıt değiştiyse, işlemi iptal eder, kilidi açar ve kullanıcıyı uyarırsınız.


Bu en pratik yaklaşım gibi geliyor. Bunu uygulayan herhangi bir çerçeveyi biliyor musunuz? Bu programla ilgili en büyük sorunun, basit bir "düzenleme çatışması" mesajının kullanıcıları sinirlendireceği, ancak değişiklikleri (el ile veya otomatik olarak) birleştirmeyi denemenin zor olduğunu düşünüyorum.
paj28

Ne yazık ki, bunu kutunun dışında destekleyen herhangi bir çerçeve bilmiyorum. Düzenlenmiş bir derleme hata iletisinin sık sık ortaya çıkmadığı sürece sinir bozucu olarak algılanacağını sanmıyorum. Nihayetinde, sadece zaman damgasını kontrol etmek veya daha karmaşık bir birleştirme fonksiyonu uygulamak istediğiniz sistemin kullanıcı yüküne bağlıdır.
Phil

İnce taneli yaklaşımı kullanan bir PC dağıtılmış veritabanı ürününü tuttum (yerel veritabanı kopyasına karşı): eğer bir kullanıcı fiyatı değiştirirse, diğeri açıklama değiştirirse - sorun değil! Tıpkı gerçek hayatta olduğu gibi. İki kullanıcı fiyatı değiştirirse - 2. kullanıcı bir özür alır ve değişikliğini tekrar dener. Sorun değil! Bu, verilerin veritabanına yazıldığı an haricinde kilit gerektirmez. Değişikliklerin ekranda olduğu ve bir kullanıcının daha sonra gönderdiği bir kullanıcının öğle yemeğine gidip gitmemesi önemli değildir. Uzak veritabanı değişiklikleri için, kayıt zaman damgalarına dayanıyordu.

1
Dataflex, tanımladığınız şeyi yapan "reread ()" adlı bir işleve sahipti. Daha sonraki sürümlerde, çok kullanıcılı bir ortamda güvenli idi. Ve aslında, böyle bir araya getirilmiş güncellemeleri işe almanın tek yolu buydu.

sql sunucusuyla bunun nasıl yapılacağına bir örnek verebilir misiniz? \
l

10

2 ana yol gördüm:

  1. Kullanıcının gizli bir girişte düzenlediği sayfanın son güncellemesinin zaman damgasını ekleyin. Zaman damgası işlenirken geçerli olana göre denetlenir ve eşleşmezse, başkası tarafından güncellenir ve bir hata döndürülür.

    • pro: birden fazla kullanıcı sayfanın farklı bölümlerini düzenleyebilir. Hata sayfası, ikinci kullanıcının değişikliklerini yeni sayfada birleştirebileceği farklı bir sayfaya yol açabilir.

    • con: büyük eşzamanlı düzenlemeler sırasında bazen büyük çaba harcanıyor.

  2. Bir kullanıcı sayfayı düzenlemeye başladığında, makul bir süre boyunca kilitlediğinde, başka bir kullanıcı düzenlemeye çalıştığında bir hata sayfası alır ve kilitlenme süresi doluncaya veya ilk kullanıcı tarafından işlenene kadar beklemesi gerekir.

    • pro: düzenleme çabaları boşa harcanmaz.

    • con: ahlaksız bir kullanıcı bir sayfayı süresiz olarak kilitleyebilir. Süresi dolan kilidi olan bir sayfa, aksi belirtilmediği sürece yine de işleyebilir (teknik 1'i kullanarak).


7

İyimser Eşzamanlılık Denetimi'ni kullanın .

Söz konusu tabloya bir versionNumber veya versionTimestamp sütunu ekleyin (tamsayı en güvenlidir).

Kullanıcı 1 kayıt okur:

{id:1, status:unimportant, version:5}

Kullanıcı 2 kayıt okur:

{id:1, status:unimportant, version:5}

Kullanıcı 1 kaydı kaydeder, bu sürümü arttırır:

save {id:1, status:important, version:5}
new value {id:1, status:important, version:6}

Kullanıcı 2, okudukları kaydı kaydetmeye çalışır:

save {id:1, status:unimportant, version:5}
ERROR

Hazırda Bekletme / JPA bunu @Versionek açıklama ile otomatik olarak yapabilir

Okuma kaydının durumunu bir yerde, genellikle oturumda tutmanız gerekir (bu, gizli bir form değişkeninden daha güvenlidir).


Teşekkürler ... @Version hakkında bilmek özellikle yararlı. Bir soru: Devleti oturumda saklamak neden güvenli? Bu durumda, geri düğmesini kullanmanın işleri şaşırtmasından endişe ediyorum.
paj28

Oturum, kullanıcı sürüm değerini değiştiremediğinden gizli bir form öğesinden daha güvenlidir. Bu bir endişe değilse, o zaman oturum hakkındaki kısmı görmezden
gelin

Bu tekniğe İyimser çevrimdışı kilit adı verilir ve SQLAlchemy'de de bulunur
paj28

@ paj28 - Bu bağlantı SQLAlchemyiyimser çevrimdışı kilitler hakkında hiçbir şey göstermez ve dokümanlarda bulamıyorum. Daha yararlı bir bağlantınız var mıydı yoksa genel olarak SQLAlchemy'de insanları işaret ediyor musunuz?
Dwanderson

@dwanderson Bu bağlantının sürüm sayacı kısmını kastediyordum.
paj28,

1

Bazı Nesne İlişkisel Eşleme (ORM) sistemleri, bir nesnenin hangi alanlarının veritabanından yüklendiğinden beri değiştiğini algılar ve yalnızca bu değerleri ayarlamak için SQL güncelleme deyimini oluşturur. Ruby on Rails için ActiveRecord böyle bir ORM'dir.

Net etki, kullanıcının değiştirmediği alanların veritabanına gönderilen UPDATE komutuna dahil edilmemesidir. Farklı alanları aynı anda güncelleyen insanlar, birbirlerinin değişikliklerinin üzerine yazmazlar.

Hangi programlama dilini kullandığınıza bağlı olarak, hangi ORM'lerin kullanılabilir olduğunu araştırın ve bunlardan herhangi birinin uygulamanızda "kirli" olarak işaretlenmiş veritabanındaki sütunları güncelleyip güncellemeyeceğini görün.


Selam greg. Maalesef bu, bu tür yarış koşullarında yardımcı olmuyor. Orijinal örneğimi dikkate alırsanız, Alice kaydettiğinde, ORM fiyat sütununu kirli olarak görecek ve güncelleme istemese de güncelleyecektir.
paj28

1
@ paj28 Greg'in cevabındaki kilit nokta " kullanıcının değişmediği alanlardır ". Alice fiyatı değiştirmedi, bu yüzden ORM veritabanındaki "fiyat" değerini kaydetmeye çalışmadı.
Ross Patterson

@RossPatterson - ORM, kullanıcının değiştirdiği alanlar ile tarayıcıdaki verileri eski alanların arasındaki farkı nasıl biliyor? En azından fazladan bir izleme yapmadan yapmaz. Greg'in cevabını bu izlemeyi içerecek şekilde düzenlemek veya başka bir cevap göndermek istiyorsanız, bu yararlı olacaktır.
paj28

@ paj28 sistemin bir kısmının kullanıcının ne yaptığını bilmesi ve yalnızca kullanıcının yaptığı değişiklikleri kaydetmesi gerekir. Eğer kullanıcı fiyatı değiştirdi, sonra geri değiştirdi, sonra gönderdi, bu "kullanıcının değiştirdiği bir şey" olarak sayılmamalıydı, çünkü yapmadılar. Bu düzeyde eşzamanlılık kontrolü gerektiren bir sisteminiz varsa, bu şekilde inşa etmeniz gerekir. Değilse, hayır.

@nocomprende - Bazı bölümler, elbette - ama bu cevabın dediği gibi ORM değil
paj28
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.