Rails + MySQL + Transactions + Locking,如何防止打开事务解锁表?

bmc*_*mck 6 mysql innodb locking transactions ruby-on-rails

在我的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
Run Code Online (Sandbox Code Playgroud)

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

来自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.
Run Code Online (Sandbox Code Playgroud)

Ran*_*eed 2

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

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

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

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