【问题标题】:Rails + MySQL + Transactions + Locking, how do I prevent opening a transaction from unlocking the table?Rails + MySQL + Transactions + Locking,如何防止打开事务解锁表?
【发布时间】:2013-06-04 20:44:02
【问题描述】:

在我的 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.

【问题讨论】:

    标签: mysql ruby-on-rails transactions locking innodb


    【解决方案1】:

    我会假设另一个请求将由另一个进程处理,或者至少通过另一个连接(到 MySQL)来处理(抱歉,我对 Ruby-on-rails 一无所知)。

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

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

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

    【讨论】:

      【解决方案2】:

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

      希望对你有帮助

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2016-08-14
        • 1970-01-01
        • 2011-05-12
        相关资源
        最近更新 更多