2012-03-11 2 views
1

Я следую этому учебнику, http://ruby.railstutorial.org/chapters/modeling-users?version=3.2#top, который мне очень нравится, но в нем упоминается что-то о атрибуте уникальности, которого я не получаю. Это мю пользовательский файл до сих пор:Ruby Tutorial и «уникальность»

class User < ActiveRecord::Base 

    #these attributes can be modified by the users 
    attr_accessible :name, :email; 

    #validation testing 
    validates :name, presence: true, length: { maximum: 50 } 
    #regular expression (there is an official one) 
    VALID_EMAIL_REGEX = /\A[\w+\-.][email protected][a-z\d\-.]+\.[a-z]+\z/i 
    #and add it.. 
    validates :email, presence: true, format: { with: VALID_EMAIL_REGEX }, 
     uniqueness: { case_sensitive: false } 

end 

Он говорит:

"Использование Подтверждает:. Уникальность не гарантирует уникальность

Алиса случайно нажмет на„Отправить“дважды, отправляя два запроса в быстрая последовательность. Выполняется следующая последовательность: запрос 1 создает пользователя в памяти, который проходит проверку, запрос 2 делает то же самое, запрос пользователя 1 сохраняется, запрос пользователя 2 сохраняется. Результат: две записи пользователя с одинаковым адресом электронной почты , несмотря на uniquenes s валидация ".

Я попытался создать 2 пользователей с тем же адресом электронной почты, используя консоль (и метод User.create), и уникальность, казалось, сработала, поскольку только первый из них попал в sqlite3. Итак, что может привести к ошибке или уникальности?

ответ

4

Я считаю, что цель, которую пытается сделать учебник, состоит в том, что проверка уникальности выполняется с помощью уровня приложения, а не базы данных. Если у вас была система, которая могла обрабатывать несколько запросов одновременно, то: проверка уникальности страдает от так называемого состояния гонки.

Способ уникальности заключается в том, чтобы (1) запросить базу данных для соответствующей записи. Если совпадающая запись не найдена, выполняется проверка и (2) запись сохраняется в базе данных. Между этапами (1) и (2) теоретически возможно, хотя и маловероятно, для другого запроса напасть и добавить соответствующую запись в базу данных.

Проблему можно избежать, также применяя уникальность в базе данных. Как это сделать, зависит от базы данных, которую вы используете; Rails не помогает вам в этом.

1

Если у вас есть два экземпляра RoR говорит на тот же сервер SQL, там может быть следующий сценарий:

process A reads, no email like '[email protected]' 
process B reads, no email like '[email protected]' 
process A writes new User with '[email protected]' 
process B writes new User with '[email protected]' 

Рубин не поддерживает более одного Thread в то время, поэтому вам нужны два отдельных Процессы RoR.

Эта проблема может быть решена, если вы пишете свое принудительное применение в SQL или используете DataMapper вместо ActiveRecord.

+0

C-Ruby (MRI и YARV) не использует собственные потоки, кроме зеленых потоков. Альтернативные реализации, такие как JRuby или Rubinius, используют собственные потоки. Однако оба типа могут наблюдать состояние гонки в одном процессе. –

0

Ограничение терпит неудачу, когда два параллельных процесс пытается сохранить конфликтующие объекты

Process 1     Process 2 

1. Create Object in Memory 
2.        Create Object in Memory 
3.        Check DB -> valid 
4. Check DB -> valid 

Теперь оба процесса думает, что они проверены их ограничение уникальности и по-прежнему сохранить объект.

5. save 
6.        save 

Проблема в том, что оба процесса проверяют уникальность перед сохранением своих объектов. Таким образом, оба процесса видят, что во время проверки конфликт отсутствует. Конфликт начинается только после шага 5. Теперь проблема заключается в том, что он не проверяется на этапе 6, а процесс 6 таким образом сохраняет недопустимый объект, который не соответствует уникальному ограничению.

Чтобы уменьшить это, вы можете создать уникальный индекс в своей базе данных.Это определенно гарантирует, что вы не можете вставить недопустимые данные в свой db, поскольку ограничение проверяется базой данных в атомарном, так что условие гонки больше не встречается.

Теперь вы можете положиться только на этот уникальный индекс. Однако вы заметите, что при возникновении ошибки вы не получите сообщений об ошибках. Поэтому на практике вы должны использовать и то, и другое. Поэтому для большинства случаев вы можете положиться на прекрасно интегрированное уникальное ограничение рельсов. Для редких случаев условий гонки вы можете рассчитывать на уникальный индекс, чтобы убедиться, что ваши данные сохраняются в 100% случаев.

Смежные вопросы