2016-06-09 22 views
0

我知道有與唯一索引如何解決RoR中validates_uniqueness_of中的競爭條件?

validates_uniqueness_of :attribute 
RoR中

的,因爲在罕見的情況下,競爭狀態的問題,有兩個要求,一個緊隨另一個。

我讀過的解決方案是爲每個模型請求設置一個單獨的唯一索引,這會在競態條件下引發錯誤。

我不明白這是如何工作的。 如果人A提出請求,那麼人B,他們得到相同的索引?這是如何運作的?

回答

2

由於rails無法鎖定數據庫並且經常同時運行多個線程,所以發生競態條件。

要了解競爭條件是如何發生的,想想什麼是需要一個唯一性檢查,我給兩個線程的一個例子:

讓我們假設人A和B要保存新具有屬性name的BlogPost,它必須是唯一的。

  1. 某甲點擊保存按鈕
  2. 某乙點擊保存按鈕
  3. Rails的開始是去和查詢數據庫,看看是否 有與名稱的任何相關博客文章「我的博客帖子」
  4. 線程A
  5. Rails的開始是去和查詢數據庫,看看是否有與名稱的任何相關博客文章線程B「我的博客帖子」
  6. 線程A返回「不,與該名稱沒有相關博客文章,無不昭示着拯救」
  7. ŧ hread乙返回「不,與該名稱沒有相關博客文章,無不昭示着拯救」
  8. 線程A節省了個人博客帖子一
  9. 所以確實線程B

...現在有兩家相關博客文章與同名。

沒有什麼能夠阻止這種情況發生,這是因爲「lookup [」和「save」動作是兩個單獨的事情,因此可能會以上述方式發生。

但是...當你把一個唯一的索引在數據庫上...什麼情況是這樣的:

  1. 某甲點擊保存按鈕
  2. 某乙點擊保存按鈕
  3. Rails的開始是去和查詢數據庫,看看是否 有與名稱的任何相關博客文章「線程A我的博文」
  4. Rails的開始是去和查詢數據庫,看看是否有與名稱的任何相關博客文章線程B‘我的博客帖子’
  5. 線程A返回‘不,與該名稱沒有相關博客文章,無不昭示着拯救’
  6. 線程B返回「不,與該名稱沒有相關博客文章,無不昭示着拯救」
  7. 線程A節省了個人博客帖子一
  8. 線程B試圖保存博客帖子,但數據庫說「不!我失敗了唯一性約束」

結果:只有一個博客帖子名爲

現在 - 些什麼你問...什麼我假設是錯誤的理解......和指標。不是ID。 每個記錄沒有得到相同的索引。 沒有記錄得到的指數。

可以有點假裝指數是已經被設定此列的所有值的查找表。

對於非唯一索引i會發生什麼s你有一個所有值的列表......以及哪些記錄具有該值的列表。例如:

小工具: 顏色:藍色 IDS:1,3,7 綠色標識:2,4 紅色標識:5,6

(完全是編造的例子,一點也不像現實)

當指數具有唯一性約束,它只是具有相同的名單,但只允許數據庫來存儲每個值一個 ID,如果你嘗試存儲一個又一個......它拋出一個異常

+2

使用'UNIQUE'約束也意味着你需要成爲pr仔細閱讀步驟8,您將在保存時發現異常。儘量不要讓你的應用程序隨意爆炸,如果這是預料之中的,並從一個有意義的錯誤中恢復。 – tadman

+0

Ah so Peron A正在保存到DB的第7列,而B人將訪問同一第7列......這是發生競爭狀態的標誌!非常感謝! @tadman是的,謝謝你的提醒:)我一定會把頁面從該錯誤中保存 – innhyu