2009-06-08 2 views
6

Я хотел бы использовать подготовленные заявления для many reasons. Но, я хотел бы создать метод, который выглядит следующим образом:Зачем мне нужно подключение для создания PreparedStatements?

/* This opens a connection, executes the query, and closes the connection */ 
public static void executeNonQuery(String queryString); 

Другими словами, я хочу, чтобы моя логика приложения только должны формулировать запросы и подачи в параметрах, но не иметь дело с соединениями & заявления , Однако PreparedStatements создаются из объекта соединения, поэтому в настоящее время я вынужден подготовить строку запроса, используя String.format() - butt уродливый и опасный.

Есть ли способ делать то, что я хочу, без использования String.format()?

+0

Ваш метод executeNonQuery имеет одну проблему: получение соединения. Если вы создаете его каждый раз, когда этот метод выполняется, у вас будут проблемы с производительностью снова и снова (создание и закрытие соединений дорого). Если это инкапсулировано на объект, который создает соединение только при первом вызове, у вас возникнет проблема: когда его закрыть? Может быть, в зависимости от времени? Если вы используете статические поля для кеширования, будьте осторожны, это не будет собрано. Остерегайтесь одновременных вызовов при кешировании соединения: без механизма блокировки (например, synchhonized) вы можете создавать множество подключений. –

ответ

14

Зачем мне нужно подключение для создания PreparedStatements?

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

Подготовленные заявления на самом деле представляют собой кэшированные планы выполнения, которые не учитывают разрешения, кодировки, настройки сортировки и т. Д.

Все это выполняется во время разбора запроса.

Есть ли способ сделать то, что я хочу без использования String.format()

Не понимаю, почему вам нужно String.format() здесь.

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

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

SELECT * 
FROM table 
WHERE col1 = ? 
     AND col2 = ? 

, где связанные параметры будут заменены на ?-х во время выполнения запроса.

Если вы хотите static метод:

  • Создать ручку с static соединения.
  • Создайте хеш-таблицу static подготовленных запросов с использованием параметризованного текста запроса как key, а дескриптор подготовленного запроса - value.
  • Всякий раз, когда вы хотите выполнить запрос, найдите его дескриптор (или создайте его, если он не был найден) и используйте для привязки параметров и выполнения запроса.
1

Почему бы не использовать логику «приложения» для создания слоя данных, который вы можете создать таким способом интерфейса?

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

Я думаю, что если вы пытаетесь объединить параметры в своем запросе/заявлении самостоятельно в строку, то вы стреляете в ногу и фактически не используете функциональные возможности параметра PreparedStatements. Не знаете, почему вы хотели бы это сделать.

Возможно, вы также захотите ознакомиться с использованием API, такого как Spring, который имеет ряд классов JdbcTemplate, которые могут абстрагировать всю обработку соединений от вас, но все же позволяют работать с параметрами в Map.

0

Я освещаю все вещи JDBC, имея класс, который я вызываю QueryRunner, который имеет метод execute, который принимает sql, Список объектов, представляющих параметры, и объект, который будет обрабатывать ResultSet. Если вы используете метод setObject из JDBC для установки ваших параметров, он будет определять соответствующие типы БД для использования на основе базового объекта. Вот часть моего кода. У меня есть другой метод, который обертывает это и получает соединение.

public void executeNoCommit(Connection conn, 
          String sql, 
          List params, 
          ResultSetProcessor processor) throws SQLException { 
    PreparedStatement stmt = null; 
    ResultSet rs = null; 
    int updateCount = 0; 
    Iterator it; 
    int paramIndex = 1; 
    boolean query; 

    try { 
     stmt = conn.prepareStatement(sql); 

     if (params != null) { 
      it = params.iterator(); 
      while (it.hasNext()) { 
       stmt.setObject(paramIndex, it.next()); 
       paramIndex++; 
      } 
     } 

     query = stmt.execute(); 
     if (query) { 
      rs = stmt.getResultSet(); 
     } 
     else { 
      updateCount = stmt.getUpdateCount(); 
     } 

     processor.process(rs, updateCount); 
    } 
    finally { 
     if (rs != null) { 
      try { 
       rs.close(); 
      } 
      catch (SQLException e) { 
       log.error(e); 
      } 
     } 

     if (stmt != null) { 
      try { 
       stmt.close(); 
      } 
      catch (SQLException e) { 
       log.error(e); 
      } 
     } 
    } 
} 
+0

Можете ли вы отправить код? – ripper234

0

Вы, вероятно, хотите что-то вроде пакета DbUtils в библиотеках Apache Commons: [http://commons.apache.org/dbutils/index.html][1]

Класс QueryRunner позволяет выполнять операторы SQL без необходимости вручную создавать PreparedStatements, или даже открытое соединение для этого дело. На странице примеров:

QueryRunner run = new QueryRunner(dataSource); 
try 
{ 
    // Create an object array to hold the values to insert 
    Object[] insertParams = {"John Doe", new Double(1.82)}; 
    // Execute the SQL update statement and return the number of 
    // inserts that were made 
    int inserts = run.update("INSERT INTO Person (name,height) VALUES (?,?)", 
           insertParams); 

    // Now it's time to rise to the occation... 
    Object[] updateParams = {new Double(2.05), "John Doe"}; 
    int updates = run.update("UPDATE Person SET height=? WHERE name=?", 
           updateParams); 
} 
catch(SQLException sqle) { 
    // Handle it 
} 

Так что в основном обрабатывает создание подготовленных заявлений прозрачно, и единственное, что вам действительно нужно знать, это DataSource. Это также работает так же, как и для операторов без обновления/вставки, т. Е. Простых запросов на ваниль, а возможность создания ResultSetHandlers дает вам возможность конвертировать ResultSet во что-то вроде полностью подготовленного компонента или карту с ключами это имена столбцов, а значения - это фактические значения строк. Очень полезно, когда вы не можете реализовать все решение ORM.

Смежные вопросы