Зачем мне нужно соединение для создания PreparedStatements? - PullRequest
7 голосов
/ 08 июня 2009

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

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

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

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

Ответы [ 4 ]

14 голосов
/ 08 июня 2009

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

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

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

Все это делается при разборе запроса.

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

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

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

Параметризованный запрос обычно выглядит так:

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

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

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

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

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

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

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

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

0 голосов
/ 08 июня 2009

Возможно, вы хотите что-то вроде пакета 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.

0 голосов
/ 08 июня 2009

Я абстрагирую все вещи 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);
            }
        }
    }
}
...