2012-03-11 45 views
1

我一直在關注本教程,http://ruby.railstutorial.org/chapters/modeling-users?version=3.2#top,我覺得它很棒,但它提到了一些我不明白的唯一性屬性。 這也是迄今爲止畝用戶文件:Ruby教程和「唯一性」

class User < ActiveRecord::Base 

    #these attributes can be modified by the users 
    attr_accessible :name, :email; 

    #validation testing 
    validates :name, presence: true, length: { maximum: 50 } 
    #regular expression (there is an official one) 
    VALID_EMAIL_REGEX = /\A[\w+\-.][email protected][a-z\d\-.]+\.[a-z]+\z/i 
    #and add it.. 
    validates :email, presence: true, format: { with: VALID_EMAIL_REGEX }, 
     uniqueness: { case_sensitive: false } 

end 

它說:

「使用只會驗證:唯一不保證唯一性

愛麗絲不小心點擊‘提交’兩次,送兩個請求快速繼續 發生以下情況:請求1在內存中創建一個通過驗證的用戶,請求2執行相同操作,請求1的用戶得到保存,請求2的用戶得到保存 結果:具有完全相同電子郵件地址的兩條用戶記錄,儘管uniquenes的驗證。「

我嘗試使用控制檯(和User.create方法)使用相同的電子郵件地址創建2個用戶,唯一性似乎工作正常,因爲只有第一個進入sqlite3。那麼,什麼會導致錯誤或唯一性失敗?

回答

4

我相信教程試圖做的一點是唯一性驗證是由應用程序層而不是數據庫執行的。如果您有一個可以同時處理多個請求的系統,則唯一性驗證會遭受所謂的競爭條件。

唯一性的工作方式是(1)在數據庫中查詢匹配的記錄。如果找不到匹配的記錄,則驗證通過,並且(2)記錄保存到數據庫。在步驟(1)和(2)之間,理論上可能的是,雖然不太可能,但是另一個請求可以突襲並向數據庫添加匹配記錄。

該問題也可以通過在數據庫中實施唯一性來避免。如何做到這一點取決於你正在使用的數據庫; Rails不協助你這樣做。

1

如果你有聊到相同的SQL服務器回報率的兩個實例,可能有以下情形:

process A reads, no email like '[email protected]' 
process B reads, no email like '[email protected]' 
process A writes new User with '[email protected]' 
process B writes new User with '[email protected]' 

紅寶石不支持在同一時間超過一個Thread,因此,你需要兩個獨立的RoR流程。

如果您在SQL中編寫唯一性實施或使用DataMapper而不是ActiveRecord,則可以解決此問題。

+0

C-Ruby(MRI和YARV)不使用原生線程,而是使用綠色線程。像JRuby或Rubinius這樣的替代實現使用本地線程。但是,這兩種類型都可以在單一過程中觀察比賽情況。 – 2012-03-11 20:41:16

0

約束當兩個並行的進程嘗試保存衝突對象

Process 1     Process 2 

1. Create Object in Memory 
2.        Create Object in Memory 
3.        Check DB -> valid 
4. Check DB -> valid 

現在,這兩個過程認爲,他們已經證明了他們的唯一性約束,繼續保存對象失敗。

5. save 
6.        save 

現在的問題是,兩個進程在保存它們的對象之前檢查唯一性。所以這兩個流程都會在檢查時看到沒有衝突。衝突僅在步驟5之後開始存在。現在的問題是,它在步驟6中未被檢查,因此過程6保存了不符合唯一約束的無效對象。

爲了緩解這種情況,您可以在數據庫上創建唯一的索引。這肯定會確保您無法將無效數據插入到數據庫中,因爲數據庫以原子方式檢查約束,因此競爭條件不再發生。

現在你只能依靠那個唯一索引。但是,您會注意到如果發生錯誤,您將不會收到很好的錯誤消息。所以在實踐中你應該使用兩者。因此,對於大多數情況,您可以依賴軌道的完美集成唯一約束。對於極少數的競爭條件,您可以依靠唯一的索引來確保您的數據在100%的時間內節省。