在独立Java应用程序中创建连接池

时间:2016-07-15 18:40:44

标签: java jdbc connection pool

我需要在独立(如非Web)Java应用程序中使用连接池。在我工作的地方,我们不允许在不经过安全层的情况下使用API​​,而且工作需要尽快完成。以下是我尝试创建此连接池。

我已对该代码进行了单元测试,并在整个应用程序的上下文中对其进行了一百次测试,并且在所有情况下测试均通过零错误进行测试,此外,每次运行的性能比一次运行快三千倍。简单连接,检索数据,串行连接断开;然而,我仍然担心这种方法可能存在问题,而我还没有挖掘出来。我将不胜感激任何有关以下代码的建议。这是我在这个网站上的第一篇文章;如果我在礼节上犯了任何错误,请告诉我。在发布之前我确实在这个网站上搜索了这个问题。请参阅下面的调用示例代码。谢谢。 --JR

package mypackage;

import java.sql.Connection;
import java.sql.SQLException;
import java.util.Map;
import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.TimeUnit;

/**
 * Note: This class is only instantiated once per application run.
 *       Multiple instantiations, as specified in the release notes,
 *       are not supported.      
 */
public class ConnectionManager {

    // Use a blocking queue to store the database connections.
    // The application will only be called once, by a single user,
    // but within the application many threads will require 
    // a connection. 
    private BlockingQueue<Connection> connectionQueue = null;

    // Load the connection queue with a user-defined number of connections.
    // Params contains a map of all non hard-coded variables in the
    // application.
    public ConnectionManager(int howMany, Map<String, Object> params) {
        Database database = new Database();
        connectionQueue = new ArrayBlockingQueue<Connection>(howMany);
        for(int i = 0; i < howMany; i++) {
            connectionQueue.add(database.getConn(params));
        }
    }

    // Return a connection from the queue, waiting up to 15 minutes to do so.
    // 15 minutes is hard-coded because it is the standard time-out for all
    // processes at our agency.  This application must complete in less
    // than fifteen minutes (is currently completing in thirty five seconds).
    public Connection getConnection() {
        Connection conn = null;
        try {
            conn = connectionQueue.poll(15, TimeUnit.MINUTES);
        }
        catch(InterruptedException e) {
            e.printStackTrace();
        }
        catch(SQLException e) {
            e.printStackTrace();
        }
        return conn;
    }

    // Returns a connection to the connection queue.  
    public void returnConnectionToManager(Connection conn) {
        connectionQueue.add(conn);
    }

    // Called on the last line of the application program's dispatcher.
    // Closes all active connections (which will only exist if there
    // was a failure within one of the worker threads).
    public void closeAllConnections() {
        for(Connection conn : connectionQueue) {
            try {
                conn.close();
            }
            catch(SQLException e) {
                e.printStackTrace();
            }
        }
    }
}

调用示例:

...

private ConnectionManager cm;

...

public Table(Map<String, Object> params, String method) {
  ...
  cm = (ConnectionManager) params.get("cm");
}

// Execute a chunk of SQL code without requiring processing of a 
// result set.  Acquires connection from pool via cm.getConnection
// and releases connection via cm.returnConnectionToManager.
// (Database is just a helper class with simple methods for 
// closing prepared statement, result sets, etc.)  
private void execute(String sql) {
  PreparedStatement ps = null;
  Connection conn = null;
  try {
    conn = cm.getConnection();
    ps = conn.prepareStatement(sql);
    ps.execute();
  }
  catch (SQLException e) {
    e.printStackTrace();
  }
  finally {
    database.closePreparedStatement(ps);
    cm.returnConnectionToManager(conn); 
  }
}

1 个答案:

答案 0 :(得分:0)

你的代码看起来不错,但是有一个严重的问题,你的API的客户端需要处理获取和释放连接,其中一个忘记了,内存/资源泄漏已经准备就绪。

在一个地方发布您要执行的查询,在此处进行连接,执行查询并将连接返回到池中。它将确保您返回连接。如果需要在单个连接中一个接一个地调用多个查询,则使该方法接受要按顺序执行的SQL查询的数组或列表。我们的想法是将每个请求封装到数据库中,以便管理所有连接。你可能想要编写一个你需要实现的连接(连接conn)的接口,然后你可以使用一些服务来获取这个对象给它一个连接,然后将资源释放回连接池。 类似的东西:

interface SqlWork {
 execute(Connection conn);
}

SqlWork myWork = new SqlWork () {
  execute(Connection conn) {
    // do you work with the conn here
  }
}

class SqlExecutionService {
   ConnectionManager cm = ...;

   public void execute(SqlWork sqlWork) {
       Connection conn = null;
       try {
         conn = cm.getConnection();
         sqlWork.execute(conn);
       } catch (Your exceptions here) {
         //serve or rethrow them
       }
       finally 
       {
         if (conn!=null) { 
           cm.returnConnectionToManager(conn); 
         }
       }
   }
}

使用示例:

SqlExecutionService sqlExecService = ...;
sqlExecService.execute(myWork);