JDBC и обработка ошибок

errorОшибки, как известно, случаются. И случаются они без нашего желания, поэтому остаётся их только обрабатывать.

SQLException

использует стандартный механизм для работы с ошибками: исключения. В .sql заведена целая новая иерархия исключений, прародителем которой является SQLException.

SQLException наследуется от Exception и является, таким образом, checked exception. Кроме стандартных данных, которые передаются в Exception, SQLException всегда содержит дополнительные данные о ошибке:

  • getMessage() возвращает сообщение об ошибке.
  • getSqlState() возвращает стандартный код состояния запроса. Говоря по простому — каждый раз, когда SQL база данных выполняет запрос, она присваивает этому запросу некий статус: успешно; успешно, но с предупреждениями; совсем не успешно итд. Значения этих статусов стандартизированы в XOpen SQLState convention. SQLState всегда состоит из 5 знаков, первые два знака отмечают класс состояния, оставшиеся три — подкласс состояния. Обычно классы 00 и 01 означают, что запрос выполнился нормально, остальные говорят об ошибке в запросе. Не смотря на то, что значения статусов стандартизированы, лучше проверять документацию по вашей конкретной реализации базы данных, поскольку стандарты это конечно стандарты, но всё равно все реализуют их по своему.
  • getErrorCode() возвращает номер ошибки, специфичный для вашей реализации БД.
  • getNextException() возвращает следующий SQLException в цепочке, если при исполнении запроса было сгенерировано несколько SQLException. Вызов getNextException() для последнего SQLException в цепочке возвращает его самого.

Пример обработки SQLException, возникающего при попытке вставить в таблицу некорректные данные:

Наследники SQLException подразделяются на три больших класса:

  • SQLRecoverableException — ошибка, которая может быть исправлена методом «попробуйте выключить и включить»: переустановить соединение, переповторить транзакцию итд.
  • SQLTransientException — ошибка, которая может быть исправлена при повторе операции позднее.
  • SQLNonTransientException — ошибка, которая не может быть исправлена кроме как исправлением запроса или его данных.

Особняком держится BatchUpdateException, который не относится ни к одному из трёх классов перечисленных выше и выбрасывается когда в executeBatch() возникает ошибка (или select запрос). Это исключение содержит дополнительный метод getUpdateCounts(), которые возвращает массив чисел. Каждое число массива это количество строк, на которые подействовал соответствующий запрос в наборе.

SQLWarning

SQLWarning это исключение, которое не выбрасывается. Будучи унаследованным от SQLException, SQLWarning имеет все те же самые дополнительные возможности, что и SQLException. Однако, экземпляры этого класса не выбрасываются, а запрашиваются напрямую методом getWarnings() у объектов Connection, Statement или ResultSet.

Суть в том, что SQLWarning возникает, когда ошибки как бы и нет, но вот результат может отличаться от запрошенного. Например когда MySQL получает запрос update, который ничего не изменяет, он возвращает warning, в котором говорится, что запрос ничего не изменил. В остальном SQLWarning можно обрабатывать так же, как и SQLException.

К сожалению, добиться генерации SQLWarning от H2 базы мне не удалось, поэтому примера не будет.

Код примера доступен на github.