2009-04-29 3 views
1

У меня есть приложение с большим количеством отношений базы данных, которые зависят друг от друга, чтобы успешно управлять приложением. Шарнир в приложении - это модель, называемая «Расписание», но график будет вытаскивать «Блоки», «Сотрудник», «Идентификатор задания» и «Назначение» (кроме того, каждый блок также вытаскивает назначение из базы данных вместе с ним) собрать график сотрудников в течение дня.Когда мне нужны модельные отношения, как мне защищаться от ошибок?

Когда я построил приложение, я уделял большое внимание проверкам, которые гарантировали бы, что все части должны быть на месте, прежде чем все будет сохранено в базе данных. Это до настоящего времени получилось фантастически, и приложение было живым и стучало в течение почти 6 месяцев, обслуживая около 150 000 запросов в месяц без икоты или ошибок. До последней недели.

На прошлой неделе, когда кто-то менял расписание, похоже, что база данных ошибочна, и расписание было сохранено в базе данных с отсутствующим присваиванием. Поскольку ассоциация вызывается во всех представлениях, всякий раз, когда это расписание вызывается из базы данных, приложение будет вызывать ошибку NoMethod для вызова на nil.

При разработке приложения так, как я заявляю, защищаете ли вы от возможного сбоя со стороны базы данных/валидации? И если да, то как вы программно защищаете его? Проверяете ли вы все отношения, чтобы убедиться, что он не равен нулю, прежде чем отправлять его в представление?

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

ответ

5

Я бы порекомендовал добавить database-enforced foreign key constraints и wrapping important groups of operations into transactions.

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

+0

IIRC, в большинстве БД, ограничения FK могут применяться к столбцам с нулевым значением, и в этом случае он не защитит OP от проблемы. Возможно, есть что-то конкретное в Ruby/Rails/конкретной БД, которая предотвратит это ... В моем ответе предполагается, что ограничения FK уже существуют. – rmeador

+0

Я не использую принудительные ограничения FK базы данных, только проверки Rails для обеспечения создания и существования дочерних объектов. Спасибо за информацию! Я рассмотрю ограничения FK! Я уже завершаю несколько операций с несколькими базами данных в транзакции, но моя база данных должна поддерживать транзакции, чтобы получить это преимущество, не так ли? – BushyMark

+0

Именно поэтому СУБД должна обеспечивать соблюдение ограничений - в случае, если ошибка в одном из неограниченного количества приложений имеет сбой в ней. Не совсем ясно, имеет ли расписание столбец внешнего ключа, который будет ссылаться на таблицу присваивания; Однако, если бы это произошло, вставка не удалась, и проблема не возникла. Это связано с тем, что существует одна СУБД и, вероятно, многие приложения, совместно использующие данные, которые должны выполняться СУБД, поскольку все приложения используют СУБД, и поэтому вы получаете максимальную согласованность. –

-1

Если это то, что должно быть правдой, чтобы приложение функционировало, это действительно то, что для assert(). Я почти никогда не использовал Ruby, но я полагаю, что у этого должна быть эта концепция. Используйте их для обеспечения предусловий в разных местах вашего кода. Это в сочетании с дезинфекцией и проверкой ваших внешних (пользовательских) входов должно быть достаточно, чтобы защитить вас. Я думаю, что если что-то пойдет не так после такого количества проверок, ваше приложение будет разрешено сбой (контролируемым образом, конечно).

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

5

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

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

Таким образом, если плохие данные попадают, несмотря на любые защитные меры, которые вы имеете на месте, вы будете знать о это скорее, чем позже.

+0

Мы делаем это здесь, в Stack Overflow - поскольку мы денормализуем много данных для производительности запросов, у нас есть несколько фоновых задач, которые гарантируют достоверность данных. –

+0

Это тоже фантастическая идея, я уже использую backgroundrb для подметания базы данных для удаления данных. , , добавление другого работника, чтобы я не имел осиротевших объектов, был бы большой проверкой на это! Благодаря! – BushyMark

+0

Рекомендуется иметь процедуры проверки последовательности. Но это должно быть с целью устранения проблемы, а не для очистки обломков. Если вы продолжаете видеть одни и те же плохие данные, все еще не контролируется. – dkretz

1

Я буду спорить с нетрадиционной мудростью. Ограничения, которые вы описываете, не входят в базу данных, они принадлежат вашему OO-коду.И это не так, что «база данных заблуждался», это, безусловно, верно, что приложение является то, что вставлена ​​неправильно проверенные данные.

Когда вы начинаете ожидать, что база данных нести бремя этих проверок, вы вводите бизнес-правила в схему. Как минимум, это затрудняет запись модульных тестов (именно там вы, вероятно, должны были это поймать, но теперь ваш шанс добавить еще один тест.)

В идеале вы должны быть способны для замены РСУБД некоторым другим общим хранилищем данных и до сих пор все функциональные логики должным образом активны и не изменяются в соответствующих других местах. Пользовательский интерфейс не должен разговаривать с DAL, тем более что он напрямую связан с исключениями базы данных.

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

+1

В общем, я согласен с вами, но это становится проблемой с такими вещами, как validates_uniqueness_of. Это не может гарантировать уникальность из-за нескольких одновременных процессов. –

+0

Это не проблема с одновременными процессами как таковыми, но, возможно, с несколькими процессами Ruby (я не использую ActiveRecords, поэтому не могу сказать.) Но я реализовал в значительной степени приложение планирования, которое вы описываете, и мне нужно было его спроектировать для одновременного использования пользователей, и для этого не требовалось каких-либо героических программ баз данных.Мне просто не нравится видеть популярный ответ, подразумевающий, что неизбежно, что база данных неизбежно должна иметь дело с ним, потому что он не может быть обработан в правильных слоях абстракции. К сожалению, это обычная мудрость. – dkretz

+0

Поскольку Rails является однопоточным, обычная установка Rails может иметь сотни отдельных процессов Ruby, попадающих в базу данных. Поэтому между ними, когда validates_uniqueness_of проверяет уникальность и когда запись сохраняется, идентичная запись может быть сохранена другим процессом. Прямо сейчас, если вы действительно хотите гарантировать уникальность в Rails (а вы не можете - это целая отдельная запись!), Ограничение базы данных, к сожалению, является вашим единственным выбором. –