Обработка нарушений целостности Java + MySQL
Я пишу программу на Java, используя JDBC (база данных mysql). Когда я нарушаю целостность MySQL (например, я пытаюсь вставить то же значение первичного ключа), я ловлю исключение SQL. Должен ли я писать так, чтобы этого никогда не происходило (например, сначала булева функция проверяет, не находится ли значение первичного ключа в БД, а затем вызывает вставку), или это нормально - обрабатывать это только по исключению? Пример:
catch (SQLException ex) {ex.printStackTrace(); showSomeErrorDialog(); }
3 ответа
На самом деле есть два основных способа добиться этого:
Проверьте, существует ли запись, прежде чем вставлять в ту же транзакцию.
Определите, если
SQLException#getSQLState()
пойманногоSQLException
начинается с23
что является нарушением ограничения согласно спецификации SQL. Именно это может быть вызвано большим количеством факторов, чем просто нарушение ограничения. Вы не должны исправлять каждыйSQLException
как нарушение ограничения.public static boolean isConstraintViolation(SQLException e) { return e.getSQLState().startsWith("23"); }
Я бы выбрал первый, так как он семантически более правильный. На самом деле это не исключительное обстоятельство. Вы именно знаете, что это может произойти. Но он может потенциально потерпеть неудачу в тяжелой параллельной среде, где транзакции не синхронизированы (либо неосознанно, либо для оптимизации производительности). Затем вы можете захотеть определить исключение.
Тем не менее, как правило, вы не должны получать нарушение ограничений для первичного ключа. В хорошо спроектированных моделях данных, которые используют технические ключи в качестве первичных ключей, ими обычно управляет сама база данных. Разве поле не должно быть уникальным ключом?
Есть два возможных ответа:
- если вы знаете, что ваше приложение предназначено для избежания такого поведения, используйте исключение
- если ваше приложение может часто делать эти ошибки, используйте тест.
Как уже упоминалось, есть два возможных подхода, один из которых - протестировать, а затем вставить / обновить, иначе обработать исключение SQL. Оба этих подхода имеют свои недостатки:
- Предостережение для "Тест перед вставкой" заключается в том, что каждая транзакция будет иметь дополнительные запросы, которые будут влиять на производительность. Это особенно большая проблема, когда таких ошибочных транзакций мало.
- Предостережение для "оценки исключений SQL" заключается в том, что такие сообщения об исключениях очень специфичны для базы данных. Эти сообщения, в большинстве случаев, не дают конкретной информации, кроме заявления о наличии нарушения ограничений.
Итак, я предложу подход, который является гибридом двух.
- Не выполняйте тест перед вставкой.
- Позвольте базе данных выдать исключение.
- Поймать исключение SQL.
- В потоке исключений (блок catch) выполните дополнительные запросы, чтобы сформировать очень специфические сообщения об ошибках, чтобы указать клиентам, что именно вышло из строя (уникальный ключ, первичный ключ, внешний ключ, определенные столбцы и т. Д.).
Это может потребовать несколько дополнительных строк кода, но это определенно улучшает производительность и генерирует дружественные сообщения об ошибках.