2016-02-13 73 views
2

繁忙應用程序中的API客戶端正在爭奪現有資源。他們一次請求1或2,然後嘗試對這些記錄採取行動。我試圖使用事務來保護狀態,但是無法獲得行鎖的清晰畫面,尤其是在嵌套事務(我猜是保存點,因爲PG不是確實在事務內執行事務?)。ActiveRecord和Postgres行鎖定

的過程應該是這樣的:

  • 請求N3資源
  • 從池中刪除這些資源,以防止其他用戶試圖要求他們
  • 與這些資源
  • 卷執行操作如果發生錯誤,則返回整個事務並返回資源池

(As sume所有例子的快樂路徑。請求總是導致退貨產品)

一個版本看起來是這樣的:

def self.do_it(request_count) 
    Product.transaction do 
    locked_products = Product.where(state: 'available').lock('FOR UPDATE').limit(request_count).to_a 
    Product.where(id: locked_products.map(&:id)).update_all(state: 'locked') 
    do_something(locked_products) 
    end 
end 

在我看來,我們能有對第一線死鎖如果兩個用戶請求2,只有3可用。因此,要解決它,我想做...

def self.do_it(request_count) 
    Product.transaction do 
    locked_products = [] 
    request_count.times do 
     Product.transaction(requires_new: true) do 
     locked_product = Product.where(state: 'available').lock('FOR UPDATE').limit(1).first 
     locked_product.update!(state: 'locked') 
     locked_products << locked_product 
     end 
    end 
    do_something(locked_products) 
    end 
end 

但是,從我已經成功地在網上找到的,是內部事務的end不會釋放行級鎖 - 他們只會當最外面的交易結束時被釋放。

最後,我認爲是這樣的:

def self.do_it(request_count) 
    locked_products = [] 
    request_count.times do 
    Product.transaction do 
     locked_product = Product.where(state: 'available').lock('FOR UPDATE').limit(1).first 
     locked_product.update!(state: 'locked') 
     locked_products << locked_product 
    end 
    end 
    Product.transaction { do_something(locked_products) } 
ensure 
    evaluate_and_cleanup(locked_products) 
end 

這給了我兩個完全獨立的交易之後的第三執行的動作,但我不得不做人工檢查(或者我能救)如果do_something失敗,這使事情變得更加混亂。如果有人在交易中致電do_it,這也可能導致死鎖,這很可能發生。

所以我的大問題:

  • 是我行鎖釋放的理解是否正確?只有在最外層事務處理關閉時纔會釋放嵌套事務中的行鎖定?
  • 是否有一個命令可以在不關閉事務的情況下更改鎖定類型?

我的小問題:

有一些在這裏建立或完全明顯的模式是正在跳躍出來給別人更多的三立處理呢?

回答

1

事實證明,通過潛入PostgreSQL控制檯並處理事務處理來回答這些問題非常容易。

要回答的大問題:

,我行鎖的理解是正確的。在保存點內獲取的獨佔鎖不會在釋放保存點時釋放,而是在整個事務提交時釋放。

,沒有改變鎖定類型的命令。那會是什麼樣的魔法?一旦你有一個獨佔鎖,所有會觸及該行的查詢都必須等待你釋放鎖,然後才能繼續。

除了提交事務,回滾保存點或事務也將釋放獨佔鎖。

在我的應用程序中,我通過使用多個事務並在應用程序中非常仔細地跟蹤狀態來解決了我的問題。這爲重構提供了一個很好的機會,並且代碼的最終版本更簡單,更清晰並且更容易維護,儘管它的代價是比「全面投入」 PG交易「方法。