rails中的线程(?)数据库锁定(?)

时间:2009-09-29 02:46:07

标签: ruby-on-rails locking thread-safety

说我有这个方法:

def create_registration_unless_over_limit
  if Registration.count < 50
    Registration.create!
  else
    raise "too many registrations"
  end
end

考虑到我有多个rails进程正在运行,我如何确保我从未进行过&gt; = 50次注册?从理论上讲,两个请求几乎不可能同时进入,都运行if语句并查看&lt; 50个注册是真的,然后他们都创建了新的注册?

2 个答案:

答案 0 :(得分:2)

对于你的特定情况,只要忽略这个问题:)我99.99%确定你真的不在乎你有50或51个注册:) 在更一般的情况下,您需要使用一些锁定。

SELECT count(*) FROM registrations FOR UPDATE

如果另一个线程执行了它并且仍然在事务中,则上述查询将阻止。

不幸的是'count'方法的ActiveRecord :: Base不支持:lock参数(嗯,为什么?)。所以你需要使用count_by_sql。请在2个独立的终端屏幕中尝试以下操作:

./script/runner 'Registration.transaction {puts "counting...";c = Registration.count_by_sql("select count(*) from registrations for update");puts "count = #{c}. press enter to continue";gets}'

当第一个运行将停在'按下进入'阶段时,第二个应该阻止在'计数...'阶段,直到你释放第一个。

答案 1 :(得分:0)

存储过程以创建行,如果&lt; 50,否则返回故障代码

或者!

创建一个创建帐户的队列系统,确保一个进程始终在创建帐户