Логика: база данных или приложение / 2 (проверка ограничений)

StackOverflow https://stackoverflow.com/questions/167154

  •  03-07-2019
  •  | 
  •  

Вопрос

Это конкретная версия этого вопроса .
Я хочу проверить, вставляю ли я повторяющуюся строку. Должен ли я проверить это программно на уровне приложения:

if (exists(obj))
{
    throw new DuplicateObjectException();
}
HibernateSessionFactory.getSession().save(obj);

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

try
{
    HibernateSessionFactory.getSession().save(obj);
}
catch(ConstraintViolationException e)
{
    throw new DuplicateObjectException();
}

РЕДАКТИРОВАТЬ: Другими словами: несмотря на то, что ограничение есть, оно остается (в любом случае это хороший дизайн базы данных, и я не могу быть уверен, что мое приложение будет единственным, получающим доступ к таблице). полагаться на ограничение и обрабатывать исключение, которое вызовет его нарушение, или я все равно лучше проверю?

EDIT2: Конечно, я проверяю + вставляю внутри транзакции, блокируя таблицу, чтобы убедиться, что никакой другой процесс не записывает другую запись за это время

Это было полезно?

Решение

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

Учитывая, что ограничение существует, каким образом вы должны кодировать в приложении? Я предпочел бы попробовать вставить и поймать исключения. Поскольку, предположительно, большинство вставок выполнятся успешно, только несколько из них завершатся с ошибками в виде дубликатов (это то, что подразумевает «исключение»!): Неэффективно выполнять проверку на существование перед каждой вставкой, когда база данных все равно будет выполнять свою собственную проверку ограничений .

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

Другие советы

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

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

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

РЕДАКТИРОВАТЬ . Возможно, я неправильно понял вопрос, но я все равно утверждаю, что вариант B (HibernateSessionFactory выдает исключение ConstraintException из базы данных) является лучшим вариантом. Всегда есть небольшой шанс, что другое приложение может вставить что-то за промежуток времени между проверкой и фактическим вызовом функции. Кроме того, единственный способ проверить наличие дублирования - это выполнить дополнительный запрос, который просто излишне снижает производительность.

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

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

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

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

Исключения, создаваемые Hibernate (или любым компонентом ORM), трудно интерпретировать.

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

Если в исключении недостаточно информации, необходимо проверить состояние ошибки и предоставить пользователю полезное сообщение об ошибке, что он что-то делает не так.

Вопрос в том, насколько непрозрачным является исключение? Некоторые из них довольно непрозрачны. У других достаточно, чтобы вы могли разобрать строку сообщения и выяснить, что сказать пользователю.

После того, как hibernate сгенерирует исключение из сеанса, вы должны сбросить сеанс (см. раздел 11.2.3). Итак, если вам нужно проверить наличие дупсов и продолжить использовать тот же сеанс, то у вас нет выбора, кроме как сначала проверить в приложении.

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

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top