【问题标题】:Good practices: JDBC Connection [duplicate]良好实践:JDBC 连接 [重复]
【发布时间】:2011-11-08 23:56:55
【问题描述】:

可能重复:
when to close Connection, Statement, PreparedStatement and ResultSet in 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's 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,所有PreparedStatements 和 他们的ResultSets 也关门了,对吧?

用法:

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 吗?设计不错?

【问题讨论】:

  • 关闭和重新打开每个查询的连接是个坏主意。建立联系真的非常非常昂贵。
  • 那么我可以让 PreparedStatement 保持打开状态,还是应该为每个查询关闭它?
  • 您可以让一切保持打开状态,直到您真正完成使用数据库。关闭连接将跟踪并关闭它产生的所有内容(语句、结果集)。
  • 您可能只使用 Jakarta Commons DBUtils。它似乎和你的包装器做同样的事情。

标签: java jdbc


【解决方案1】:

您必须在完成后关闭 PreparedStatement,然后再在同一连接上创建新的。我遇到了严重的问题,因为我没有关闭 PreparedStatements。事实证明,在数据库服务器上分配的资源只有在显式调用 PreparedStatement.close() 后才会释放。

正如 bdares 评论的那样,连接应该尽可能不频繁地打开和关闭。

【讨论】:

  • 这是不正确的。 1.您可以同时拥有多个PreparedStatements。 2. 关闭连接会自动关闭所有语句和结果集。 3. Connection 应尽可能频繁地打开和关闭,并通过使用 Apache DBCP 等连接池降低性能。
【解决方案2】:

连接池

使用连接池。您应用中的每个事务都会从该池中获得一个连接,执行所有需要的操作,回滚或提交并关闭连接(它将连接返回池)。

你可以给你 Query 对象一个对池的引用,open 将获得连接,close 将关闭它(实际上是返回它)。

准备好的声明

尝试将您准备好的语句重用于类似的查询。这样数据库将重用以前的查询计划,它会更快。如果您要执行大量相同形式的查询,这很有意义。

怎么做?

  • 保持上次打开 PS
  • 如果您关闭连接或其他什么,请关闭它
  • 如果您查询的查询字符串与上一次相同的查询字符串重用您保存的 PS
  • 如果不是同一个查询字符串...关闭它并创建一个新的

【讨论】:

    【解决方案3】:

    使用连接池。所以你不要继续创作。

    【讨论】:

    • 连接池是在我初始化数据库的时候创建的。我的 database.open() 方法返回的连接是来自池的连接,因为我使用的是数据源。
    【解决方案4】:

    最好的做法是:如果这些查询是同一方法的一部分,并且每个查询在使用后关闭 PreparedStatement,则对所有查询使用单个 Connection 对象。

    【讨论】:

      猜你喜欢
      • 2011-06-14
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2019-01-18
      • 2011-03-09
      • 2015-06-09
      相关资源
      最近更新 更多