4

我们在 Rails 应用程序中遇到了竞争条件问题。在我解释之前,这里有一些(简化的)代码:

class Message < ActiveRecord::Base
  belongs_to :question
end

class Question < ActiveRecord::Base
  has_many :messages

  def create_or_update_sending_message
    sending_message = messages.detect {|m| m.status == 'sending'}
    sending_message ||= messages.create :status => 'sending'
    sending_message
  end

  def validate
    errors.add_to_base('cannot have multiple sending messages') if messages.select {|m| m.status == 'sending'}.count > 1
  end
end

正在发生的事情是create_or_update_sending_message从两个进程中调用的。两者都将消息集合视为空,因此都创建了一条新消息。然后第三个进程加载问题,修改它,尝试保存它,我们在一个不是实际问题发生的地方抛出一个错误。

如果我们从头开始设计,我可以想出一些方法来避免这种情况,但不幸create_or_update_sending_message的是,遗留代码太深而无法实用。

我们为问题模型启用了乐观锁定。它没有帮助,因为问题没有被保存 - 只有它的消息被保存。

有没有办法在问题上使用乐观锁定来防止保存消息的创建?所以它看起来像

def create_or_update_sending_message
  self.optimistically_lock do |lock|
    sending_message = messages.detect {|m| m.status == 'sending'}
    sending_message ||= messages.create_with_optimistic_lock lock, :status => 'sending'
    sending_message
  end
end

从数据库的角度来看,这是否有意义?

4

0 回答 0