Слезы и боль

При работе Java-программы могут возникать ошибки. При работе с базой данных ошибки будут возникать. Все дело лишь в том, какие из них ты можешь предсказать и предложить адекватное решение.

Первая большая группа ошибок будет тебя ждать при выполнении этой строчки:

Connection connection  = DriverManager.getConnection("jdbc:mysql://localhost:3306/test",  "root", "secret");

Что вас тут может ожидать?

Ошибка 1. Драйвер не найден.

Если ты получил ошибку “No suitable driver found for …” это значит, что DriverManager не смог понять какой тип СУБД скрывается за вашим URL. Например, ты написал jdbc_mysql: вместо jdbc:mysql:

Ошибка 2. Ошибка соединения.

Если ты допустил ошибку в имени хоста, то, скорее всего, получишь сообщение типа “No such host is known” или “Communications link failure”.

Ошибка 3. Неверно указано имя базы данных.

Если ты допустил опечатку в имени базы данных или подключаешься к другому серверу, где ее нет, то получишь сообщение типа “Unknown database 'supershop3'”.

Ошибка 4. Неверный логин или пароль.

Если ты забыл пароль от базы или неверно его указал, то, скорее всего, получишь сообщение типа “Access denied for user 'root'@'localhost' (using password: YES)”.

SQL Exception

Если соединение с базой все же установилось, то дальше будет интереснее. На случай ошибок при работе с базой у JDBC есть специальные исключение – java.sql.SQLException. А также несколько ее разновидностей.

У этого исключения есть только один дополнительный метод (в сравнении с классом Exception) – это метод getSQLState(), который возвращает код состояния (строку), который вернул ему SQL-сервер. Обработка ошибок при этом выглядит так:

Connection connection  = DriverManager.getConnection("jdbc:mysql://localhost:3306/test",  "root", "secret");
try {
   int rowsCount = statement.executeUpdate("DELETE FROM ‘Unemployees’");
} catch (SQLException ex) {
  // Если таблица не существует
   if (ex.getSQLState().compareTo("X0Y32") != 0) {
  	throw ex;
  }
 } finally {
  connection.close();
 }

Кодов ошибок при этом несколько сотен. Полный список можешь посмотреть тут.

Но иногда коды ошибок помогают JDBC понять ошибку лучше и тогда он создает не просто SQLException, а специализированные SQLException:

BatchUpdateException Ошибка во время группового запроса
DataTruncation Часто возникает при обрезании длинных данных
SQLClientInfoException Клиент передал параметры, которые не могут быть установлены у соединения: Connection
SQLDataException Ошибка с данными, детали зависят от типа СУБД
SQLException Ошибка доступа к базе или другие общие ошибки
SQLFeatureNotSupportedException СУБД не поддерживает данную функциональность
SQLIntegrityConstraintViolationException Все ошибки с для SQLState ==22
SQLInvalidAuthorizationSpecException Ошибка доступа и/или авторизации
SQLNonTransientConnectionException Все ошибки с для SQLState ==08
SQLRecoverableException Ошибка есть, но ее можно исправить при вмешательстве application
SQLSyntaxErrorException Ошибка в синтаксисе запроса
SQLTimeoutException Запрос выполнялся слишком долго
SQLTransactionRollbackException Ошибка во время отката транзакции
SQLWarning Предупреждение, которое выслала СУБД

Примеры ошибок

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

Есть два самых больших классов ошибок при работе с базой данных:

  • Ошибка в тексте запроса
  • Ошибка при работе с ResultSet

Ошибка в тексте запроса может возникать очень часто. Запрос может быть очень длинным, содержать несколько таблиц (объединенных через JOIN) и подзапросов (SUBSELECT). Найти ошибку в таком запросе непросто. Кроме того, запросы часто склеиваются из частей, туда добавляются данные.

Самая первая ошибка, о которой тебе следует знать, — это SQLSyntaxErrorException. Такая ошибка обычно значит, что у тебя опечатка в теле запроса.

Возьмем наш любимый пример:

ResultSet results = statement.executeQuery("SELECT Count(*) FROM user");
results.next();
    int count = results.getInt(1);

И “случайно” сотрем звездочку в теле запроса:

ResultSet results = statement.executeQuery("SELECT Count() FROM user");
results.next();
    int count = results.getInt(1);

Тогда мы получим исключение:

Exception in thread "main" java.sql.SQLSyntaxErrorException:

You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near ') FROM task' at line 1

           	at com.mysql.cj.jdbc.exceptions.SQLError.createSQLException(SQLError.java:120)

SQL-сервер пишет нам, что перед FROM была синтаксическая ошибка.

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

Еще одна популярная ошибка — неправильная работа с ResultSet — результатом запроса. Допустим ты забыл, что перед чтением данных “текущая строка” объекта ResultSet стоит перед первой строкой, то у тебя будет такой код:

ResultSet results = statement.executeQuery("SELECT Count(*) FROM user");
//    results.next();
    int count = results.getInt(1);

Ты получишь такую ошибку:


2012 12:55:48 AM jButton5ActionPerformed
SEVERE: null
java.sql.SQLException: Before start of result set
    at com.mysql.jdbc.SQLError.createSQLException(SQLError.java:1073)
    at com.mysql.jdbc.SQLError.createSQLException(SQLError.java:987)
    at com.mysql.jdbc.SQLError.createSQLException(SQLError.java:982)
    at com.mysql.jdbc.SQLError.createSQLException(SQLError.java:927)
    at com.mysql.jdbc.ResultSetImpl.checkRowPos(ResultSetImpl.java:841)
    at com.mysql.jdbc.ResultSetImpl.getStringInternal(ResultSetImpl.java:5650)
    at com.mysql.jdbc.ResultSetImpl.getString(ResultSetImpl.java:5570)

Внимательно смотрим на ошибку и думаем. Затем гуглим и находим пару примеров и пытаемся понять решение.