【问题标题】:Database locking: ActiveRecord + Heroku数据库锁定:ActiveRecord + Heroku
【发布时间】:2011-02-08 15:17:56
【问题描述】:

我正在构建一个基于 Sinatra 的应用程序,用于在 Heroku 上进行部署。你可以把它想象成一个标准的 URL 缩短器,但是旧的短代码过期并可以用于新的 URL(我意识到这是一个愚蠢的概念,但这样更容易解释)。我将我的数据库中的简码表示为一个整数,并重新定义它的阅读器以从整数中给出一个漂亮的短且唯一的字符串。

由于某些行将被删除,我编写了遍历所有短代码整数的代码,并选择第一个免费的仅使用before_save。不幸的是,如果我一个接一个地快速运行两个实例,我可以让我的代码创建两行具有相同短代码整数的行,这显然是不好的!我应该如何实现一个锁定系统,以便我可以使用唯一的短代码整数快速保存我的记录?

这是我目前所拥有的:

Chars = ('a'..'z').to_a + ('A'..'Z').to_a + ('0'..'9').to_a
CharLength = Chars.length

class Shorts < ActiveRecord::Base
  before_save :gen_shortcode
  after_save  :done_shortcode

  def shortcode
    i = read_attribute(:shortcode).to_i

    return '0' if i == 0
    s = ''
    while i > 0
      s << Chars[i.modulo(CharLength)]
      i /= 62
    end
    s
  end

  private
  def gen_shortcode
    shortcode = 0
    self.class.find(:all,:order=>"shortcode ASC").each do |s|
      if s.read_attribute(:shortcode).to_i != shortcode
        # Begin locking?
        break
      end
      shortcode += 1
    end

    write_attribute(:shortcode,shortcode)
  end

  def done_shortcode
    # End Locking?
  end
end

【问题讨论】:

    标签: ruby activerecord locking heroku


    【解决方案1】:

    这一行:

    self.class.find(:all,:order=>"shortcode ASC").each
    

    将对您的整个记录​​集合进行顺序搜索。您必须锁定整个表,以便当您的一个进程正在扫描下一个整数时,其他进程将等待第一个完成。这将是一个性能杀手。如果可能的话,我的建议是流程如下:

    1. 添加一列,指示记录何时过期(您是否按创建时间使它们过期?最后一次使用?)。索引此列。
    2. 当您需要找到下一个最低可用数字时,请执行以下操作

      Shorts.find(:conditions => {:expired => true},:order => 'shortcode')

    这将使数据库努力寻找最低的过期短代码。回想一下,在没有 :all 参数的情况下,find 方法将只返回第一个匹配的记录。

    现在,为了防止进程之间的竞争条件,您可以将其包装在事务中并在执行搜索时锁定:

    Shorts.transaction do
        Shorts.find(:conditions => {:expired => true},:order => 'shortcode', :lock => true)
        #Do your thing here. Be quick about it, the row is locked while you work.
    end #on ending the transaction the lock is released
    

    现在,当第二个进程开始寻找免费短代码时,它不会读取被锁定的短代码(因此它可能会找到下一个)。这是因为 :lock => true 参数获得了排他锁(读/写)。

    查看this guide 了解有关使用 ActiveRecord 锁定的更多信息。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2015-11-26
      • 2011-02-28
      • 2023-03-26
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多