Логика: база данных или приложение / 2 (проверка ограничений) - PullRequest
8 голосов
/ 03 октября 2008

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

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

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

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

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

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

Ответы [ 7 ]

7 голосов
/ 03 октября 2008

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

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

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

2 голосов
/ 03 октября 2008

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

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

2 голосов
/ 03 октября 2008

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

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

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

1 голос
/ 03 октября 2008

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

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

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

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

1 голос
/ 03 октября 2008

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

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

1 голос
/ 03 октября 2008

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

0 голосов
/ 03 октября 2008

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

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

...