2014-02-08 3 views
0

Мой следующий код:Когда я использую рубин мьютекса, но данные все еще повторяют

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. Пожалуйста, помогите мне ...

+0

что вы имеете в виду то же самое msg_id? Вы когда-нибудь использовали уникальный столбец msg_id в db? –

+0

Это не имеет никакого отношения к мьютексам, которые используются для предотвращения одновременного доступа нескольких потоков к общему ресурсу. Это не будет препятствовать выполнению кода дважды, если 'index' вызывается дважды. –

+0

Просто добавьте уникальный индекс в 'msg_id', а затем поймайте исключение в' save! '(Или' create! 'Вместо' new'/'save!') –

ответ

0

Все зависит от того, как вы запускаете свой сервер. Рельсы работают как однопоточное приложение с большинством серверов. Существуют серверы (например, passenger), которые запускают сервер как multi process, что означает, что параллелизм достигается за счет запуска нескольких сервисов. В больших масштабах экземпляры могут выполняться на кластере (разные машины).

Во всех этих случаях создание Mutex не приведет к тому, что вы ищете. Объем созданного вами Mutex выполнен в рамках одного процесса.

Чтобы убедиться, что вы не имеете в дб тот же msg_id, вы должны сделать проверку в БД (например, с использованием уникального столбца, использование хранимых процедур, etc.)

0

Что сказал Ури Агасси,

в большинстве случаев просто уникальный валидатор рельсам будет делать и уникальное ограничение будет просто дать вам больше головной боли, если применяется по умолчанию, так как они могут привести к регрессии на уровне базы данных,

однако, для остальных 1% случаев единственный способ справиться с этим надежно - с уникальным ограничением в e. В основном:

  1. поставить ограничение уникальности на msg_id колонки
  2. попытку вставить два же msg_id через консоль, посмотрит, какие исключения происходит, обратите внимание на класс исключения и сообщение об исключении, выяснить, как отличить msg_id уникальные ошибки ограничений из других уникальных ошибок ограничений
  3. и затем сделать спасательный блок для него, что делает обновление или что-то в этих строках

Шаг 3 на Oracle, например, с помощью вам нужно спасти соответствующий класс исключения, а затем проверить, соответствует ли сообщение об исключении уникальному ограничению соответствующего столбца, например e.message =~ /I_MSG_ID_UNIQUE_CONSTRAINT/

Точный код будет зависеть от конкретной базы данных, но в значительной степени этот рабочий процесс