class Defect < ApplicationRecord
has_many :work_orders, dependent::destroy
end
class WorkOrder < ApplicationRecord
belongs_to :fect
before_save :default_values
def default_values>>
self.running_number = self.defect.work_orders.maximum(:running_number)。 to_i 1 if self.new_record?
結束。
結束。
理想情況下,代碼是這樣的
Defect A
- 工單流水號 1
- 工單running_number2
- 工單running_number 3
缺陷B
- 工單running_number 1 工單running_number 1 缺陷B
- 工單流水號2
- 工單流水號3
然而,當多個用戶同時保存屬于同一缺陷的不同工單物件時,running_number將變得混亂,因為max_running_number只基于保存的資料。 我怎樣才能使running_number正常保存呢?
uj5u.com熱心網友回復:
問題是你的并發保存得到了相同的工單數,所以你得到了工單的重復running_numbers。
你可以通過兩種方式來解決:
running_number和defect_id要在rails遷移中設定一個唯一約束。add_index :work_orders, [:defect_id, :running_number], unique: true。然后,如果你在呼叫save時出現錯誤,就重試保存。
假設你使用的是Postgres
begin
# ...創建工單。
work_order.save
rescue PG::UniqueViolation
重試 重試
結束
使用retry將重試該塊,直到沒有產生唯一的違反。如果記錄上有其他的唯一違反錯誤,這可能會導致死鎖,所以要確保錯誤是由running_number引起的,而不是其他。
另一種方法是獲取一個鎖來防止競賽條件。由于它是一個共享資源的資料庫表,你要獲取一個表鎖,以確保在你計算工單數量和保存記錄時沒有其他行程在使用工單表。
假設你使用Postgres explicit-lock docs
ActiveRecord::Base.transaction do
#創建訂單。
ActiveRecord::Base.connection.execute('LOCK work_orders IN ACCESS EXCLUSIVE MODE'/span>)
work_order.save
結束。
用這種模式獲得一個表鎖,將阻止其他連接到資料庫的表的所有訪問。它將在事務提交時被釋放,但是如果Ruby行程在有機會完成事務塊之前因某種原因被殺死,也可能導致死鎖。
轉載請註明出處,本文鏈接:https://www.uj5u.com/net/307612.html
標籤:
下一篇:不會列印出所有的字串
