Главная » Spring » Использование JDBC совместно со Spring

0

Существует множество технологий хранения данных. Hibernate, iBATIS и JPA – лишь некоторые из них. Несмотря на немалое коли- чество вариантов, записывать Java-объекты прямо в базу данных – это уже немного старомодный путь для заработка. Стоп, а как же люди теперь зарабатывают деньги?! А, проверенным дедовским ме- тодом – сохраняя данные с помощью старого доброго JDBC.

А почему бы и нет? JDBC не требует владения языком запросов другого фреймворка. Он основан на SQL – языке доступа к данным. Плюс при использовании JDBC можно куда более точно настроить производительность доступа к данным в сравнении с любыми дру- гими технологиями. И JDBC позволяет пользоваться всеми преиму- ществами конкретных особенностей базы данных, тогда как другие фреймворки могут препятствовать этому или даже запрещать.

Более того, JDBC дает возможность работать с данными на го- раздо более низком уровне, чем прочие фреймворки доступа к дан- ным, позволяя, например, манипулировать отдельными столбцами в базе данных. Такие широкие возможности доступа к данным могут пригодиться, например, в приложениях создания отчетов, где нет смысла преобразовывать данные в объекты, чтобы затем вновь из- влекать эти данные из объектов, преобразуя их практически к ис- ходному виду.

Но не все так безоблачно в мире JDBC. К его мощности, гибкости, и простоте прилагаются некоторые недостатки.

Борьба с разбуханием JDBC-кода

Несмотря на то что JDBC API действует в тесном контакте с ба- зой данных, ответственность за управление всем, что касается до- ступа к базе данных, возлагается на программиста. Сюда входят: управление ресурсами базы данных и обработка исключений.

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

Листинг 6.1. Использование JDBC для вставки строки в базу данных

private static final String SQL_INSERT_SPITTER =

"insert into spitter (username, password, fullname) values (?, ?, ?)"; private DataSource dataSource;

public   void   addSpitter(Spitter   spitter)   { Connection conn = null; PreparedStatement  stmt  =  null;

try  {

conn = dataSource.getConnection(); // Получить соединение

stmt = conn.prepareStatement(SQL_INSERT_SPITTER); // Создать запрос stmt.setString(1,  spitter.getUsername());    // Связать  параметры

stmt.setString(2,  spitter.getPassword()); stmt.setString(3, spitter.getFullName());

stmt.execute();                         // Выполнить запрос

} catch (SQLException e) {                 // Обработать исключение (как-нибудь)

// выполнить что-нибудь… хотя… не уверен, что тут можно сделать

}  finally  {

try  {

if (stmt != null) {              // Освободить ресурсы stmt.close();

}

if (conn  !=  null)  { conn.close();

}

}  catch  (SQLException  e)  {

// Я  еще  менее  уверен,  что  тут  можно  сделать

}

}

}

Святые угодники! Более 20 строк кода, чтобы вставить простой объект в базу данных. При этом сами операции JDBC выглядят проще некуда. Неужели обязательно писать так много строк, что- бы выполнить простейшую операцию? Конечно же нет. В действи- тельности здесь лишь несколько строк реализуют вставку. Но JDBC требует корректной обработки соединений и запросов, а также воз- можного исключения SQLException.

Что касается исключения SQLException: беда в том, что здесь со- вершенно не понятно, как его обрабатывать (поскольку неочевидны проблемы, вызвавшие его), но вы вынуждены дважды предусматри- вать его обработку! Его следует перехватить на случай, если ошибка возникла в момент вставки новой записи, и снова перехватить его при закрытии запроса и соединения. Слишком сложно, особенно если учесть, что некоторые ошибки не могут быть обработаны программно.

Теперь посмотрим на фрагмент в листинге 6.2, выполняющий об- новление строки в таблице Spitter с применением традиционного подхода к использованию JDBC.

Листинг 6.2. Использование JDBC для обновления строки в базе данных

private static final String SQL_UPDATE_SPITTER =

"update spitter set username = ?, password = ?, fullname = ?"

+  "where  id  =  ?";

public   void   saveSpitter(Spitter   spitter)   { Connection conn = null; PreparedStatement  stmt  =  null;

try  {

conn = dataSource.getConnection(); // Получить соединение

stmt = conn.prepareStatement(SQL_UPDATE_SPITTER); // Создать запрос stmt.setString(1,  spitter.getUsername());     //  Связать  параметры

stmt.setString(2, spitter.getPassword()); stmt.setString(3, spitter.getFullName()); stmt.setLong(4,  spitter.getId());

stmt.execute();                       // Выполнить запрос

} catch (SQLException e) {                // Обработать исключение (как-нибудь)

// Все еще не верен, что можно было бы предложить здесь

}  finally  {

try  {

if (stmt != null) {          // Освободить ресурсы stmt.close();

}

if (conn  !=  null)  { conn.close();

}

}  catch  (SQLException  e)  {

// и здесь

}

}

}

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

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

Листинг 6.3. Использование JDBC для извлечения строки из базы данных

private static final String SQL_SELECT_SPITTER =

"select id, username, fullname from spitter where id = ?"; public  Spitter  getSpitterById(long  id)  {

Connection conn = null; PreparedStatement  stmt  =  null; ResultSet  rs  =  null;

try  {

conn = dataSource.getConnection(); // Получить соединение

stmt = conn.prepareStatement(SQL_SELECT_SPITTER); // Создать запрос stmt.setLong(1,  id);                // Связать  параметры

rs = stmt.executeQuery();        // Выполнить запрос Spitter   spitter   =   null;

if (rs.next()) {                         // Обработать  результаты spitter  =  new  Spitter(); spitter.setId(rs.getLong("id")); spitter.setUsername(rs.getString("username")); spitter.setPassword(rs.getString("password")); spitter.setFullName(rs.getString("fullname"));

}

return spitter;

} catch (SQLException e) {                // Обработать исключение (как-нибудь)

}  finally  {

if(rs !=  null) {

try {                                     // Освободить  ресурсы rs.close();

} catch(SQLException e) {}

}

if(stmt  !=  null)  { try  {

stmt.close();

} catch(SQLException e) {}

}

if(conn  !=  null)  { try  {

conn.close();

} catch(SQLException e) {}

}

}

return null;

}

Данный пример содержит такую же массу шаблонного кода, как и предыдущие примеры, и даже больше. Это словно принцип Паре- то1, перевернутый с ног на голову: чтобы выполнить запрос-строку, необходимо написать 20 процентов программного кода, тогда как оставшиеся 80 процентов – просто шаблонный код.

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

1   http://ru.wikipedia.org/wiki/Закон_Парето.

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

Источник:   Уоллс К., Spring в действии. – М.: ДМК Пресс, 2013. – 752 с.: ил.

По теме:

  • Комментарии