检查activerecord是否锁定在“更新”状态

时间:2013-02-15 01:13:05

标签: ruby-on-rails multithreading locking rails-activerecord rails-postgresql

我们说我有以下实体和关系:

A<-B<-C<-D<-E

对于相同的A(E属于A到D,C和B),我有很多E

我有一个代码片段,如下所示:

eList=E.all
varA=eList.first.D.C.B.A

E.transaction do
  ...Operations that take some time...

  varA.update_attributes(::last_update=>Time.now)
end

现在认为这个代码片段与线程一起运行。每个E实体一个线程。这意味着,如果我有一个A的10 E,那么10个线程将在此片段的同时运行。

我的问题来自

varA.update_attributes(:last_update=>Time.now)

当我查看我的代码时,我发现我有这个:

[DEBUG] 2013/02/13 13:09:51 [66222] - abstract_adapter.rb:198 -   A Update (3107.1ms)   UPDATE "A" SET "updated_at" = '2013-02-13 13:09:47.932899', "last_update" = '2013-02-13 13:09:47.932209' WHERE "id" = 144
[DEBUG] 2013/02/13 13:09:54 [48600] - abstract_adapter.rb:198 -   A Update (6812.2ms)   UPDATE "A" SET "updated_at" = '2013-02-13 13:09:47.218032', "last_update" = '2013-02-13 13:09:47.217421' WHERE "id" = 144
[DEBUG] 2013/02/13 13:09:56 [66190] - abstract_adapter.rb:198 -   A Update (6717.5ms)   UPDATE "A" SET "updated_at" = '2013-02-13 13:09:49.328496', "last_update" = '2013-02-13 13:09:49.327777' WHERE "id" = 144
[DEBUG] 2013/02/13 13:09:59 [66219] - abstract_adapter.rb:198 -   A Update (10816.2ms)   UPDATE "A" SET "updated_at" = '2013-02-13 13:09:48.236539', "last_update" = '2013-02-13 13:09:48.235895' WHERE "id" = 144
[DEBUG] 2013/02/13 13:10:01 [66200] - abstract_adapter.rb:198 -   A Update (13450.9ms)   UPDATE "A" SET "updated_at" = '2013-02-13 13:09:47.584182', "last_update" = '2013-02-13 13:09:47.583467' WHERE "id" = 144

正如您所看到的,每个线程运行每个查询的时间都会增加。第一个需要3秒,而最后一个需要13个。我认为这是因为我正在更新相同的记录(A.id = 144)所以记录被锁定而其他线程需要等待。

我的问题是,在Rails 2.3中是否有一种方法可以检测记录是否被锁定,因为它正在被更新,所以我可以让其他线程跳过更新?

类似的东西:

if not varA.locked then varA.update_attributes(:last_update=>Time.now) end

我只需更新一次就足够了所以我希望其他线程检查它是否已经更新并继续。

FWIW,我的数据库是postgres 9.0

1 个答案:

答案 0 :(得分:2)

检查行是否被锁定以进行更新是PostgreSQL中相对复杂的过程,据我所知,只能在可以捕获sql异常的过程语言中使用。如果ActiveRecord可以做到这一点,我会非常惊讶。

如果需要这样做,您可能需要编写存储过程来捕获这些异常并将其删除到SQL。