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

Передовая практика: подключение JDBC

Возможный дубликат:
когда нужно закрыть Connection, Statement, PreparedStatement и ResultSet в JDBC

Я написал простую оболочку для подключения JDBC, и она работает, но я хочу улучшить ее с помощью лучших практик, насколько это возможно. В основном он имеет такие методы, как open(), close(), isOpened(), select(), insert(), update(), delete() и batch(). Для простоты я отправлю здесь первые 4 метода.

public class Query{
    private Connection con;
    private PreparedStatement ps;
    private ResultSet rs;

    //Database.open() returns a Connection ready to use
    public void open (Database database) throws DatabaseException, SQLException{
        if (!isOpened ()){
            con = database.open ();
        }
    }

    public void close () throws SQLException{
        if (isOpened ()){
            if (ps != null) ps.close ();
            con.close ();
            con = null;
        }
    }

    public boolean isOpened (){
        return con != null;
    }

    //The query string is the query without the word "select" and can use placeholders (?)
    //The args param it just an array owith the values of this placeholders
    public ResultSet select (String query, Object[] args) throws SQLException{
        if (ps != null) ps.close ();

        if (isOpened ()){
            ps = con.prepareStatement ("select " + query);
            if (args != null){
                for (int i=0; i<args.length; i++){
                    ps.setObject (i+1, args[i]);
                }
            }
            rs = ps.executeQuery ();
        }

        return rs;
    }
}

Примечания:

  • Тот же объект запроса может быть повторно использован, например, открытие и закрытие он, и после открытия снова.
  • Я не закрываю соединение для каждого запроса, я просто закрываю подготовленное выражение (это правильно или я могу оставить подготовленный оператор открыт, потому что объект Connection закроет его?)
  • Когда я закрываю Connection, все PreparedStatement и их ResultSet также замкнуты, правильно?

Использование:

Database database;

//Database initialization

Query query = new Query ();


query.open (database);

ResultSet rs = query.select ("* from user where name=?", new String[]{ "MyName" });
doSomethingWithResult1 (rs);

//Connection is not closed here

ResultSet rs = query.select ("coordx from point where coordy=? and coordz=?", new Float[]{ 0.1, 0.2 });
doSomethingWithResult2 (rs);

query.close ();


query.open (database);

ResultSet rs = query.select ("* from user where name=?", new String[]{ "MyName" });
doSomethingWithResult1 (rs);

//Connection is not closed here

ResultSet rs = query.select ("coordx from point where coordy=? and coordz=?", new Float[]{ 0.1, 0.2 });
doSomethingWithResult2 (rs);

query.close ();

Как вы думаете? Должен ли я закрывать и открывать соединение после каждого запроса? Могу ли я оставить открытое PreparedStatement после каждого запроса в том же соединении? Это хороший дизайн?

4b9b3361

Ответ 1

Вам нужно закрыть PreparedStatement после того, как вы закончите с ним, и перед тем, как создать новый в том же соединении. У меня были серьезные проблемы, потому что я не закрывал PreparedStatements. Оказалось, что на сервере базы данных были выделены ресурсы, которые освобождаются только после явного вызова PreparedStatement.close().

Как прокомментировал bdares, соединение должно быть открыто и закрыто как можно реже.

Ответ 2

Пул соединений

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

Вы можете дать вам объект Query ссылку на пул и открыть соединение, и соединение закроет его (вернув его на самом деле).

Подготовленное выражение

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

Как?

  • Поддержание последнего открытого PS
  • Если вы закрываете соединение или что-то еще, закройте его
  • если вы запрашиваете ту же строку запроса, что и предыдущее повторное использование сохраненного вами PS
  • если это не та же строка запроса... закройте ее и создайте новую.

Ответ 3

best paectise: используйте единый объект Connection для всех запросов, если эти очереди являются частью одного и того же метода, и для каждого запроса закрыть PreparedStatement после его использования.

Ответ 4

Использовать пул соединений. Поэтому вы не продолжаете создавать.