【问题标题】:When I use ruby Mutex, but data still repeat当我使用 ruby​​ Mutex 时,数据仍然重复
【发布时间】:2023-12-22 01:57:02
【问题描述】:

我的代码是这样的:

class MessagesController < ApplicationController
@@m = Mutex.new
def index
 @@m.synchronize do
   Message.transaction do
     m = Message.find_by_msg_id(params[:msg_id])
     if m.nil?
       mess = Message.new(:msg_id => params[:msg_id], ......)
       mess.save!
       ......
     end
   end
 end
end
end

现在的问题是数据库中的消息仍然具有相同的msg_id。 请帮帮我...

【问题讨论】:

  • 同一个msg_id是什么意思?你有没有做过数据库中唯一的 msg_id 列?
  • 这与互斥锁无关,互斥锁用于防止多个线程同时访问共享资源。如果index 被调用两次,这不会阻止代码被执行两次。
  • 只需在msg_id 上添加唯一索引,然后在save! 上捕获异常(或create! 而不是new/save!
  • @user846250 将使用 db 引擎完成,只需使用唯一列,即添加迁移,这将设置列唯一。
  • 我做了db中唯一的msg_id列,但它没有使用

标签: ruby-on-rails ruby mutex synchronize


【解决方案1】:

这完全取决于您如何运行您的服务器 - rails 作为一个单线程应用程序与大多数服务器一起运行。有一些服务器(如passenger)将服务器作为多进程运行,这意味着通过运行多个服务来实现并发。在更大的范围内 - 实例可能在集群上运行(不同的机器)。

在所有这些情况下,创建Mutex 将无法实现您的目标。您创建的Mutex 的范围在同一个进程内。

为确保您在数据库中没有相同的msg_id,您必须在数据库中进行验证(如使用唯一列、使用存储过程、etc.

【讨论】:

    【解决方案2】:

    乌里·阿加西所说的,

    在大多数情况下,rails 中一个简单的唯一验证器就可以了,如果默认应用唯一约束只会让您更加头疼,因为它们会导致数据库级别的回归,

    但是,对于其余 1% 的情况,唯一可靠地处理此问题的方法是在数据库中使用唯一约束。基本上:

    1. msg_id 列上设置唯一约束
    2. 尝试通过控制台插入两个相同的msg_id,看看会发生什么样的异常,注意异常类和异常消息,弄清楚如何区分msg_id唯一约束错误和其他唯一约束错误
    3. 然后为它创建一个救援块,在这些行中执行更新或其他操作

    例如,Oracle 上的第 3 步意味着您需要拯救适当的异常类,然后检查异常消息是否与相关列的唯一约束的名称匹配,例如 e.message =~ /I_MSG_ID_UNIQUE_CONSTRAINT/

    确切的代码将取决于相关数据库,但它几乎就是这个工作流程

    【讨论】: