Обработка нарушений целостности Java + MySQL

Я пишу программу на Java, используя JDBC (база данных mysql). Когда я нарушаю целостность mysql (например, я пытаюсь вставить одно и то же значение первичного ключа), я перехватываю исключение SQL. Должен ли я написать его так, как это может никогда не произойти (например, сначала логическая функция, проверяющая, является ли значение первичного ключа еще не в БД, а затем вызывает вставку), или можно обрабатывать это только в виде исключения? Пример :

catch (SQLException ex) {ex.printStackTrace(); showSomeErrorDialog(); }

person Michal    schedule 04.02.2010    source источник
comment
Поправьте меня, если я ошибаюсь, но по умолчанию вам не нужно выполнять блок try и catch для SQLException при выполнении запросов для начала?   -  person Anthony Forloney    schedule 04.02.2010
comment
если вы выполняете запрос из инструкции, вам нужно. Оператор st = connection.createStatement(); st.executeQuery (ВЫБЕРИТЕ * ИЗ таблицы); эти потребности пытаются поймать   -  person Michal    schedule 04.02.2010
comment
Как насчет выполнения INSERT? Моя причина, по которой я спрашиваю, заключается в том, что если для выполнения запроса по умолчанию требуется блок try, вы все равно должны это сделать, но, как я уже сказал, я могу ошибаться, я вообще не работаю с JDBC.   -  person Anthony Forloney    schedule 04.02.2010
comment
вставка - это своего рода запрос, не так ли? Я не вижу специальной команды для вставки, только для обновления (не executeQuery, а executeUpdate), кроме того, что каждое выполнение выдает SQLException   -  person Michal    schedule 04.02.2010


Ответы (3)


На самом деле есть два основных способа добиться этого:

  1. Проверьте, существует ли запись перед вставкой --внутри той же транзакции.

  2. Определите, если SQLException#getSQLState() перехваченного SQLException начинается с 23, что является нарушением ограничения в соответствии с Спецификация SQL. Это может быть вызвано большим количеством факторов, чем «просто» нарушение ограничения. Вы не должны исправлять каждое SQLException как нарушение ограничения.

    public static boolean isConstraintViolation(SQLException e) {
        return e.getSQLState().startsWith("23");
    }
    

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

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

person BalusC    schedule 04.02.2010
comment
Он уникален, поэтому вставить просто не получится :) ничего страшного на самом деле не произойдет, только сообщение об ошибке - person Michal; 04.02.2010

Есть два возможных ответа:

  • если вы знаете, что ваше приложение предназначено для предотвращения такого поведения, используйте исключение
  • если ваше приложение может часто делать эти ошибки, используйте test.
person Valentin Rocher    schedule 04.02.2010
comment
С другой стороны, если приложение уже считается генерирующим уникальные ключи, то было бы вполне уместно обрабатывать сбой для этого как исключение — так как все-таки это будет считаться исключительным случаем. - person Matthew Wilson; 04.02.2010
comment
о производительности - маловероятно, что такое исключение произойдет в моем приложении. Поэтому тестирование перед каждой вставкой займет гораздо больше времени, чем просто вставка с редкими исключениями. - person Michal; 04.02.2010
comment
Я вижу, спасибо .... Я на самом деле надеялся на кого-то, кто скажет совсем другое, чем ты, бишибуш :-D Но это просто моя лень, наверное. - person Michal; 04.02.2010

Как уже упоминалось, есть два возможных подхода: один из них - протестировать, а затем вставить/обновить, иначе обработать исключение SQL. Оба этих подхода имеют свои недостатки:

  • Предостережение для «Проверить перед вставкой» заключается в том, что каждая транзакция будет иметь дополнительные запросы, которые повлияют на производительность. Это особенно большая проблема, когда таких ошибочных транзакций немного.
  • Предостережение для «Оценка исключения SQL» заключается в том, что такие сообщения об исключениях очень специфичны для базы данных. Эти сообщения в большинстве случаев не содержат конкретной информации, кроме заявления о нарушении ограничений.

Итак, я предложу подход, который представляет собой гибрид двух.

  • Не выполняйте тест перед вставкой.
  • Пусть база данных выдает исключение.
  • Перехватить исключение SQL.
  • В потоке исключений (блок перехвата) выполните дополнительные запросы, чтобы сформировать очень конкретные сообщения об ошибках, чтобы указать клиентам, что именно не удалось (уникальный ключ, первичный ключ, внешний ключ, определенные столбцы и т. д.).

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

person Bipul    schedule 02.02.2016