5

假设我有以下实体和关系:

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

对于同一个 A,我有很多 E(E 通过 D、C 和 B 属于 A)

我有一个看起来像这样的代码片段:

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

4

1 回答 1

2

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

如果你需要这样做,你可能需要编写存储过程来捕获这些异常并放到 SQL 中。

于 2013-04-26T15:45:04.023 回答