2012-07-10 7 views
10

Go altında MongoDB için mgo sürücüsünü kullanıyorum.mgo ile Go (golang) içinde MongoDB: Bir kaydı nasıl güncellerim, güncellemenin başarılı olup olmadığını öğrenmek ve verileri tek bir atom işleminde almak mı?

Uygulamam bir görevi soracaktır (Mongo'da "işler" adlı bir koleksiyondan yalnızca bir kayıt seçin) ve sonra kendini bu görev için tamamlamak üzere bir asigne olarak kaydeder (aynı "iş" kaydına yönelik bir güncelleştirme, kendini ayarlama vekil olarak).

Program, hepsi aynı Mongo'yla konuşan çeşitli makineler üzerinde çalışıyor olacak. Programım mevcut görevleri listeler ve birini seçtiğinde, diğer örnekler bu atamayı zaten almış olabilir ve geçerli atama başarısız olmuş olabilir.

Güncelleme sırasında okuduğum ve sonra güncelleştirdiğim kaydın belirli bir değeri (bu durumda, bir alıcı) içermediğinden nasıl emin olabilirim?

Tek bir ödev almaya çalışıyorum, hangisi olursa olsun, bu yüzden önce bekleyen bir görevi seçmeli ve onu atamayı denemeliyim, yalnızca güncelleştirme başarılı olduğunda bunu koru.

Yani, benim sorgu gibi bir şey olmalıdır: koleksiyonun 'işler' tüm kayıtları itibaren

" güncelleme sadece bir o vardır asignee = null, atanan olarak benim kimliği oluşturulmasını Sonra bana ver. Bu işi kayıt ederek işimi yapabilirim. "

Go için mgo sürücüsü ile bunu nasıl ifade edebilirim?

cevap

2

Umarım seçtiğiniz yanıt hakkındaki yorumları gördünüz, ancak bu yaklaşım yanlış. Bir seçim yapmak ve ardından güncelleme yapmak, bir gidiş ve iki makineyle sonuçlanacak ve bunlardan biri assignee'u güncellemeden önce aynı iş için getirilecektir. Bunun yerine findAndModify yöntemini kullanmanız gerekir: http://www.mongodb.org/display/DOCS/findAndModify+Command

+0

Aslında, ihtiyacım olan çözüm sunulan bir tux21b. Tüm "seçenekleri" geri almam, ardından birini seçmem ve sonra kendime atamayı denemeliyim. Başarısız olursa, başka biriyle deneyeceğim. –

+0

Neden TÜM seçeneklerden birini seçmelisiniz? Seçilmemiş olanı seçmeniz gerektiğini söylediniz mi (aka assignee == null)? –

+0

Haklısınız. Benim ihtiyaçlarım, soruyu yazdığımda düşündüğümden farklıydı, ama cevabınız soruyu daha iyi karşılar. –

2

MongoDB adamlar resmi belgelerinde benzer bir senaryo açıklar: http://www.mongodb.org/display/DOCS/Atomic+Operations

Temel olarak, yapmanız gereken tek şey, assignee=null ile herhangi bir işi getirme etmektir. İşi _id=42 ile geri aldığınızı varsayalım. Daha sonra belgeyi assignee="worker1.example.com" olarak ayarlayıp belgeyi {_id=42, assignee=null} seçiciniz ve güncellenmiş belgenizle Collection.Update() numaralı telefonu arayarak yapabilirsiniz. Veritabanı hala bu seçiciyle eşleşen bir belge bulabilirse, belgeyi atomik olarak değiştirecektir. Aksi takdirde, başka bir iş parçacığının görevi zaten talep ettiğini belirten bir ErrNotFound alırsınız. Bu durumda, tekrar deneyin.

+4

bir güncelleme ardından seçme Sahne atom değildir; iki gidiş-dönüş gerçekleştirir! FindAndModify komutu bu işlemi atomik olarak gerçekleştirir. Bu komut için Mongo belgelerini şu adreste bulabilirsiniz: http://www.mongodb.org/display/DOCS/findAndModify+Command Go'da bunu yapmak için Mgo belgeleri şunlardır: http://go.pkgdoc.org/labix .org/v2/mgo # Sorgu.Uygula – jorelli

+1

Seçme + güncellemenin bu özel algoritma için atomik olması gerekmez. Güncellemenin kendisi atomik olduğu sürece (temelde bir CompareAndSwap/CompareExchange işlemi) her şey yolunda. – tux21b

+1

İki makine ilk sorguda aynı işi seçerse, bunlardan biri güncellemede başarısız olur. Elbette, sonuç her zaman, veri tabanındaki verilerin hiçbir zaman tutarsız olamayacağı, ancak iki ayrı işlemin kullanılmasıyla ilgili başarısızlığın çok fazla gereksiz yere ve ileride neden olabileceğidir. Bu, findAndModify komutunun tüm nedeni. – jorelli

41

Bu eski bir sorudur, ancak birilerinin hala evde izlemesi durumunda, bu Query.Apply yöntemi aracılığıyla güzel bir şekilde desteklenir. Başka bir cevapta belirtildiği gibi findAndModify komutunu çalıştırır, ancak Go iyiliğinin ardında gizli bir şekilde saklanır.

belgelerinde örnek burada hemen hemen tam olarak soruyu eşleşir:

change := mgo.Change{ 
     Update: bson.M{"$inc": bson.M{"n": 1}}, 
     ReturnNew: true, 
} 
info, err = col.Find(M{"_id": id}).Apply(change, &doc) 
fmt.Println(doc.N) 
İlgili konular