2017-07-24 63 views
0

我一直在編寫代碼將信用從一個用戶轉移到另一個用戶,我選擇MongoDB作爲數據庫。但我被告知我在transferCredits函數中有與數據庫相關的問題。我一直在尋找,但找不到任何問題。查找與數據庫相關的問題

function transferCredits(from, to, amt) { 
    var fromAccount = db.game_accounts.findOne({"name": from},{"credits": 1}); 
    var toAccount = db.game_accounts.findOne({"name": to},{"credits": 1}); 
    if (fromAccount.credits < amt) { 
    throw new BalanceError("not enough balance to transfer credits"); 
    } 
    db.game_accounts.update({name: from}, {$set: {credits: fromAccount.credits - amt}}); 
    db.game_accounts.update({name: to}, {$set: {credits: toAccount.credits + amt}}); 
} 

db.game_accounts.insert({name: "John", credits: 1000}); 
db.game_accounts.insert({name: "Jane", credits: 1000}); 

// John transfers credits to Jane 
transferCredits("John", "Jane", 100); 
+0

無論誰告訴你可能更具體,只是說「事務」通常需要確保多個寫操作之間的一致性。儘管他們推斷「數據庫」(MongoDB)由於缺乏對交易的支持而無法處理這樣的流程,但他們的具體語言卻是由於不明身份的人所引發的那種偏見的廢話。你的「實現」有這樣的失敗,但是在不同的建模模式下很有可能在MongoDB上有這樣的「借/貸」平衡交易。你只是做不同的事情。 –

回答

0

你沒有告訴我們是什麼問題,所以我們只能猜測...

我看到的是,這部分可能是錯誤的:

db.game_accounts.update({name: from}, {$set: {credits: fromAccount.credits - amt}}); 
db.game_accounts.update({name: to}, {$set: {credits: toAccount.credits + amt}}); 

這是因爲在findOne()update()之間可能會發生另一筆交易。你最好使用$inc這將執行相同的操作,但不打開自己的比賽條件。

db.game_accounts.update({name: from}, {$inc: {credits: amt*-1}},function(err,res){ 
    if (err) throw err; 
    db.game_accounts.update({name: to}, {$inc: {credits: amt}}, function(err,res){ 
     if (err) throw err; 
     db.game_accounts.update({name: from}, {$inc: {credits: amt}}); 
    }); 
}); 

請注意,減法運算只需乘以-1即可將負數轉爲負數。

此外,如果用戶試圖給予另一個用戶-10積分,他將能夠竊取10個積分,而不是...多個其他檢查需要這樣做,以確保有效的交易。

在附註中,MongoDB並不是真正意義上的這種事務,您可能更喜歡使用另一種DB,它可以確保數據是最新的,並且所有操作都被跟蹤並完成。

+0

什麼是推測?如果您真正理解了這種非常常見的金融體系模式,那麼它基本上意味着您需要一個「配對」條目,從一個賬戶中轉移到另一個賬戶並「記賬」和「貸記」相同的金額。正如所評論的,「數據庫相關問題」是指MongoDB中的「交易」或「缺乏」。所以,如果你有兩次寫作(如同OP的問題和你的迴應一樣),那麼當其中一次失敗時會發生什麼?如果你要提交答案,你必須先**理解問題 –

+0

I編輯我的回答,以包含一種簡單的方法來處理事務,但我一直說純粹推測這個問題是關於這個確切的問題......因爲在給定的代碼片段中還有許多其他可能的問題。 – Salketer

+0

從我的閱讀中,我不認爲你理解得很好,用「MongoDB方式」來實現這一點只涉及「一次寫操作」 –