2011-09-02 175 views
12

可能重复:
when to close Connection, Statement, PreparedStatement and ResultSet in JDBC良好做法: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,所有的PreparedStatement s和 他们的ResultSet s也都关了吧?

用法:

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吗?这是一个很好的设计?

+7

关闭并重新打开每个查询的连接是一个坏主意。建立连接真的非常昂贵。 – bdares

+1

然后,我可以离开打开PreparedStatement或者我应该关闭它的每个查询? –

+0

您可以将所有内容保持打开状态,直到您实际使用数据库。关闭连接将追踪并关闭它产生的所有东西(语句,结果集)。 – bdares

回答

12

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

由于bdares评论,连接应尽可能不频繁地打开和关闭。

1

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

1

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

+0

连接池是在初始化数据库时创建的。我的database.open()方法返回的连接是来自池的连接,因为我正在使用数据源。 –

5

连接池

使用连接池。应用程序中的每个事务都将从此池中获取连接,执行所需的所有操作,回滚或提交并关闭连接(它会将连接返回到池)。

你可以给你一个查询对象池的引用,打开将获得连接,关闭将关闭它(实际上返回它)。

预处理语句

尝试重用你准备好的声明中类似的查询。这样数据库将重用先前的查询计划,并且速度会更快。如果您正在执行大量相同表单的查询,那么它有很大的意义。

怎么样?

  • 保持最后PS开放
  • 如果您关闭连接或什么的,关闭它
  • 如果查询相同的查询字符串比以前重用的PS保存
  • ,如果它是不一样的查询字符串...关闭它并创建一个新的