Подтвердить что ты не робот

Выполнение нескольких запросов с использованием одного объекта Statement JDBC

Прочтите, прежде чем отмечать это как дубликат. Я много искал у Google и SO, но я не мог точно ответить на этот вопрос.

Мой вопрос: В JDBC я могу использовать один объект Statement для вызова executeQuery("") несколько раз? Это безопасно? ИЛИ следует закрыть объект оператора после каждого запроса и создать новый объект для выполнения другого запроса.

например:

Connection con;
Statement s;
ResultSet rs;
ResultSet rs2;
try
{
    con = getConnection();
    s = con.prepareStatement();

    try
    {
        rs = s.executeQuery(".......................");

        // process the result set rs
    }
    finally
    {
        close(rs);
    }

    // I know what to do to rs here
    // But I am asking, should I close the Statement s here? Or can I use it again for the next query?

    try
    {
        rs2 = s.executeQuery(".......................");

        // process the result set rs2
    }
    finally
    {
        close(rs2);
    }
}
finally
{
    close(s);
    close(con);
}
4b9b3361

Ответ 1

Да, вы можете повторно использовать Statement (в частности, PreparedStatement) и должны делать это в общем случае с JDBC. Это был бы неэффективный и плохой стиль, если бы вы повторно не использовали ваш оператор и сразу же создали еще один идентичный объект Statement. Что касается закрытия, было бы целесообразно закрыть его в блоке finally, как и в этом фрагменте.

Пример того, что вы запрашиваете, просмотрите эту ссылку: jOOq Docs

Ответ 2

Я не уверен, почему вы спрашиваете. Конструкция и документация API показывают, что идеально подходит (и даже предназначено) для повторного использования объекта Statement для нескольких вызовов execute, executeUpdate и executeQuery. Если это не будет разрешено, это будет явно задокументировано в документе Java (и, вероятно, API будет другим).

Кроме того, apidoc Statement говорит:

Все методы выполнения в интерфейсе Statement неявно закрывают объект current [sic] current ResultSet, если существует открытый.

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

TL; DR: Да, вы можете называть execute в одиночном Statement объекте несколько раз, если вы понимаете, что все ранее открытые ResultSet будут закрыты.

В вашем примере неправильно используется PreparedStatement, и вы не можете (или: не должны) иметь возможность вызвать любой из методов execute..., принимающих String на странице PreparedStatement:

SQLException - если [...] метод вызывается на PreparedStatement или CallableStatement

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

Ответ 3

Я не могу найти что-либо в API docs, в котором указано, что вы не должны называть executeQuery() для данного PreparedStatement экземпляр более одного раза.

Однако ваш код не закрывает PreparedStatement - вызов executeQuery() будет вызывать SQLException в этом случае, но ResultSet, который возвращается executeQuery(). Функция ResultSet автоматически закрывается при повторном выполнении PreparedStatement. В зависимости от ваших обстоятельств вы должны закрыть его, когда вам это больше не нужно. Я бы закрыл его, потому что я считаю, что это плохой стиль, чтобы не делать этого.

UPDATE Упс, я пропустил ваш комментарий между двумя блоками try. Если вы закроете PreparedStatement в этот момент, вы не сможете снова вызвать executeQuery(), не получив SQLException.

Ответ 4

A Prepared Statement сообщает базе данных о необходимости помнить ваш запрос и быть готовым принять параметризованные переменные для выполнения в этом запросе. Это очень похоже на хранимую процедуру.

Prepared Statement выполняет две основные функции:

  • Он автоматически ускользает от ваших переменных запроса, чтобы помочь защитить SQL Injection.

  • Он сообщает базе данных, чтобы запомнить запрос и быть готовым к переносу переменных.

Число 2 важно, потому что это означает, что база данных должна только один раз интерпретировать ваш запрос, а затем у него есть процедура, готовая к работе. Таким образом, он улучшает производительность.

Вы не должны закрывать подготовленный оператор и/или соединение с базой данных между вызовами вызова. Это невероятно эффективно, и это вызовет дополнительные накладные расходы, чем использование простого старого Statement, поскольку вы каждый раз инструктируете базу данных о создании процедуры и ее запоминании. Даже если база данных настроена для "горячих точек" и всегда сохраняет ваш запрос, даже если вы закрываете PreparedStatement, вы по-прежнему несете сетевые издержки, а также небольшое время обработки.

Короче говоря, держите Connection и PreparedStatement открытыми, пока не закончите с ними.

Изменить: комментировать, не возвращая ResultSet из выполнения, это нормально. executeQuery вернет ResultSet для любого выполняемого запроса.

Ответ 5

Во-первых, я смущен о вашем коде

s = con.prepareStatement();

Хорошо ли работает? Я не могу найти такую ​​функцию в JAVA API, необходим хотя бы один параметр. Может быть, вы хотите вызвать эту функцию.

s = con.createStatement();

Я только что запустил свой код для доступа к DB2 в два раза с одним экземпляром Statement, не закрывая его между двумя операциями. Он работает хорошо. Я думаю, вы тоже можете попробовать.

    String sql = "";
    String sql2 = "";
    String driver = "com.ibm.db2.jcc.DB2Driver";
    String url = "jdbc:db2://ip:port/DBNAME";
    String user = "user";
    String password = "password";
    Class.forName(driver).newInstance();
    Connection conn = DriverManager.getConnection(url, user, password);
    Statement statement = conn.createStatement();
    ResultSet resultSet = statement.executeQuery(sql);
    int count = 0;
    while (resultSet.next()) {
        count++;
    }
    System.out.println("Result row count of query number one is: " + count);
    count = 0;
    resultSet = statement.executeQuery(sql2);
    while (resultSet.next()) {
        count++;
    }
    System.out.println("Result row count of query number two is: " + count);