6

在我的 Rails 代码中,我需要确认仅当剩余的某条记录超过 1 条时才允许执行某项操作。出于这个原因,我需要锁定更新,然后执行读取。我的 Rails 代码如下所示:

PaymentProfile.transaction do
  profiles = PaymentProfile.lock("LOCK IN SHARE MODE").where(user_id: xxx) 

  if profiles.count > 1
    #allow
  else
    #do not allow
  end
end

从理论上讲,这很有效,并且可以正确锁定行。但是,如果另一个请求遍历打开事务的相同代码路径,则会删除我在另一个进程中取出的锁,从而破坏了锁的目的。

来自 MySQL 文档:

Beginning a transaction also causes table locks acquired with LOCK TABLES to be released, as though you had executed UNLOCK TABLES. Beginning a transaction does not release a global read lock acquired with FLUSH TABLES WITH READ LOCK.
4

2 回答 2

2

我将假设另一个请求将由另一个进程处理,或者至少与另一个连接(到 MySQL)一起处理(对不起,我对 Ruby-on-rails 一无所知)。

一个给定事务获得的锁不能被另一个事务释放。这正是锁的目的。正如手册所说:

UNLOCK TABLES 显式释放当前会话持有的任何表锁

如果我的假设是正确的,那就没什么好担心的了。否则,如果两个请求可能同时使用同一个连接,那么这个架构中确实有一些问题......

于 2013-06-11T08:50:39.627 回答
0

也许,在这种情况下,您应该使用互斥信号量(http://www.ruby-doc.org/core-2.0/Mutex.html)以避免并发访问该共享资源(在这种情况下,它是您的PaymentProfile 处理器)。通过这样做,您将保证两个并发进程不会同时访问同步的代码块。

希望能帮助到你

于 2013-06-12T16:58:09.360 回答