连接池工作原理:
第一、连接池的建立:一般在系统初始化时,连接池会根据系统配 置建立,并在池中创建了几个连接对象,以便使用时能从连接池中获取。连接池中的连接不能随意创建和关闭,这样避免了连接随意建立和关闭造成的系统开销。 Java中提供了很多容器类可以方便的构建连接池,例如Vector、Stack等。
第二、连接池的管理。连接池管理策略是连接池机制的核心,连接池内连接的分配和释放对系统的性能有很大的影响。其管理策略是: 当客户请求数据库连接时,首先查看连接池中是否有空闲连接,如果存在空闲连接,则将连接分配给客户使用;如果没有空闲连接,则查看当前所开的连接数是否已 经达到最大连接数,如果没达到就重新创建一个连接给请求的客户;如果达到就按设定的最大等待时间进行等待,如果超出最大等待时间,则抛出异常给客户。当客户释放数据库连接时,先判断该连接的引用次数是否超过了规定值,如果超过就从连接池中删除该连接,否则保留为其他客户服务。 该策略保证了数据库连接的有效复用,避免频繁的建立、释放连接所带来的系统资源开销。
第三、连接池的关闭。当应用程序退出时,关闭连接池中所有的连接,释放连接池相关的资源,该过程正好与创建相反。
自实现连接池源码解析:
(1)数据库连接池初始化
public void init(Properties prop) throws BeenInitializedException,
ClassNotFoundException, SQLException {
if (init)
throw new BeenInitializedException(
"Database connection pool has been initialized!");
if (prop == null)
throw new NullPointerException("prop is null!");
this.url = prop.getProperty(P_URL);
this.driver = prop.getProperty(P_DRIVER);
this.username = prop.getProperty(P_USERNAME);
this.password = prop.getProperty(P_PASSWORD);
if (prop.getProperty(P_INIT_CONNECTIONS) != null)
initialConnections = Integer.parseInt(prop
.getProperty(P_INIT_CONNECTIONS));
if (prop.getProperty(P_INCREMENT_CONNECTIONS) != null)
incrementalConnections = Integer.parseInt(prop
.getProperty(P_INCREMENT_CONNECTIONS));
if (prop.getProperty(P_MAX_CONNECTIONS) != null)
maxConnections = Integer.parseInt(prop
.getProperty(P_MAX_CONNECTIONS));
logger.info("Database connection pool parameters:");
logger.info("url:" + url);
logger.info("driver:" + driver);
logger.info("username:" + username);
logger.info("password:" + password);
logger.info("initialConnections:" + initialConnections);
logger.info("incrementalConnections:" + incrementalConnections);
logger.info("maxConnections:" + maxConnections);
try {
logger.info("Load sql driver:" + driver);
Class.forName(driver);
} catch (ClassNotFoundException e) {
e.printStackTrace();
throw e;
}
logger.info("Create initialed connections:" + initialConnections);
createConnections(initialConnections);
init = true;
}
创建初始化的连接数。
/**
* 创建新连接
*
* @param num
* @throws SQLException
*/
private int createConnections(int num) throws SQLException {
int count = 0;
for (int i = 0; i < num; i++) {
if (connections.size() < maxConnections)
try {
Connection conn = DriverManager.getConnection(url,
username, password);
connections.add(new DBConnection(conn));
count++;
} catch (SQLException e) {
e.printStackTrace();
throw e;
}
}
return count;
}
(2)从连接池中获取可用连接
public synchronized Connection getConnection(long time_out_seconds) throws TimeoutException
{
logger.info("\n\nCall to get a connection from pool!"+time_out_seconds);
Connection conn = getIdledConnection();
if (conn == null) {
// 扩展连接
try {
logger.info("Non ideld connections, create more connections..");
int count = createConnections(incrementalConnections);
logger.info("Successfully create connections:" + count);
if (count > 0)
this.notifyAll();
} catch (SQLException e) {
e.printStackTrace();
}
// int count = 0;
long last = System.currentTimeMillis();
long delta = 0;
while ((conn = getIdledConnection()) == null) {
try {
delta = (time_out_seconds*1000)-(System.currentTimeMillis()-last);
// logger.info("Wait...:"+delta/1000+"s!");
if(delta <= 0){
this.notifyAll();
throw new TimeoutException();
}
this.wait(delta);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
logger.info("Last get connection:" + conn);
return conn;
} else {
logger.info("First get idled connection:" + conn);
return conn;
}
}
首先尝试从队列中获取可用的连接。
如果没有可用连接,则尝试创建更多连接,当然创建连接数不能超过最大连接数。
如果创建新的连接后还是无可用连接,则等待一段时间, 超时未获取到的话 则抛出超时异常!
(3)连接释放,返回到池中
public synchronized void release(Connection conn) {
if (conn == null)
return;
for (int i = 0; i < connections.size(); ) {
DBConnection dbCon = connections.get(i);
if (dbCon.getConnection() == conn) {
boolean is = false;
try {
is = conn.isClosed();
} catch (SQLException e) {
try {
conn.close();
} catch (SQLException e1) {
e1.printStackTrace();
}
is = true;
}
if (!is) {
dbCon.setState(0);
logger.info("A connection is released!");
i++;
}else{
connections.remove(i);
logger.info("Remove a closed connection!");
}
}else{
i++;
}
}
}
释放连接的时候,注意同时检测连接是否可用,如果连接不可用可,将其从池中移除。
(4)对Connection的进一步封装
class DBConnection {
Connection connection;
long lastTime;
int state; // 1-working 0-idel
public DBConnection(Connection conn) {
connection = conn;
lastTime = System.currentTimeMillis();
state = 0;
}
其中state主要是用于标示当前connection是否正在使用中,1表示当前连接正在被使用 0-表示当前连接空闲。
(5)从池中获取空闲连接
private Connection getIdledConnection() {
for (int i = 0; i < connections.size(); i++) {
DBConnection conn = connections.get(i);
if (conn.state == 0) {
conn.setState(1);
return conn.getConnection();
}
}
return null;
}
(6)关闭连接池
/**
* 关闭连接池
*/
public synchronized void shutDown() {
for (int i = 0; i < connections.size();) {
DBConnection dbConn = connections.remove(i);
try {
dbConn.getConnection().close();
logger.info("Close connection:" + dbConn.getConnection());
} catch (SQLException e) {
e.printStackTrace();
}
}
}