package com.sordine.meter.database;
import java.sql.Connection;
import java.util.Timer;
import java.util.Vector;
/**
* 自建数据库连接池
*
* @author 曾前林
*/
public class ConnectionPool {
private final int MIN_NUM = 15;// 最少连接数
private final int MAX_NUM = 20;// 最大连接数
private final boolean LogFlag = true;// 是否输出日志
private static int NUM = 0;// 实际连接数
private static int USE_NUM = 0;// 在使用的连接数
private static Vector databasepool = new Vector();// 自创数据库连接池
private static long MAX_IDLE = 1 * 60 * 1000;// 设置超时时间,默认3分钟,超过该时间的连接自动回收
private static Timer timer = null;// 定时器
private static boolean loginflag = true;// 判断是否是第一次创建,初始为第一次
private static boolean maxflag = true;// 判断连接池满后,是否都在使用,初始为在使用
/* 构造函数,注意调用函数的顺序 */
public ConnectionPool() {
if (loginflag) {
loginflag = false;// 第一次进来将创建连接池和定时器
timer = new Timer(true);
CreateConnections();// 创建与维护连接池
timer.schedule(new MyTask(), 1000, 30 * 1000);// 一秒钟后执行MyTask(),每30秒钟重复检查
}
}
/* 初始创建连接,以备后面的程序使用 */
public synchronized void CreateConnections() {
CreateConnection con = new CreateConnection();
/*
* 注意NUM的使用,让所有用户共有一个连接池 只有第一个人第一次使用时创建连接池,其他时间维护
*/
for (int i = NUM; i < MIN_NUM; i++) {
Connection conn = con.getConnection();
ConnectionStatus constatus = new ConnectionStatus(conn, false);// 连接对象
databasepool.add(constatus);
NUM = NUM + 1;
}
}
/*
* 从连接池获取连接 如果连接池有空闲连接,取出来用;如果没有空闲连接,等待一段时间再检查连接池
*/
public synchronized Connection getConnection() {
boolean inuse = false;// 是否使用的标志
Connection conn = null;// 连接
ConnectionStatus connstatus = null;// 连接状态
int topnum = NUM;// 定义循环的上限****重要****
for (int i = 0; i < topnum; i++) {
connstatus = (ConnectionStatus) databasepool.get(i);
conn = (Connection) connstatus.getConn();
inuse = (boolean) connstatus.getInUse();
try {
if (!conn.isClosed() && conn != null && !inuse)// 取出的连接不为空并且没有人用
{
connstatus.setInUse(true);
connstatus.setLastUsed(System.currentTimeMillis());
USE_NUM = USE_NUM + 1;// 正在使用的连接数增加1
break;
} else// 取出的连接有人在用
{
conn = null;
}
} catch (Exception e) {
System.out.println(e.toString());
}
}
if (conn == null) {
if (NUM < MAX_NUM)// 如果连接数还没有达到上限,建立新连接,加入连接池
{
CreateConnection con = new CreateConnection();
conn = con.getConnection();
ConnectionStatus constatus = new ConnectionStatus(conn, true);// 连接对象
constatus.setLastUsed(System.currentTimeMillis());
databasepool.add(constatus);
NUM = NUM + 1;// 总连接数加1
USE_NUM = USE_NUM + 1;// 正在使用的连接数增加1
} else// 否则等待连接空闲连接
{
maxflag = true;// 连接池满,并且所有连接都在使用中的状态字
while (maxflag)// 如果没有取到连接,就一直循环执行,将超时连接回收
{
CheckConnection();// 将超时连接回收
}
conn = getConnection();// 重新调用自己,取出连接
}
}
return conn;
}
/*
* 将连接还回连接池,还回的连接如果为空,将其从连接池删除
*/
public synchronized void putConnection(Connection con) {
Connection conn = null;// 将连接还回
ConnectionStatus connstatus = null;// 连接状态
int topnum = NUM;// 定义循环的上限****重要****
for (int i = 0; i < topnum; i++) {
connstatus = (ConnectionStatus) databasepool.get(i);
conn = (Connection) connstatus.getConn();
if (conn == con) {
try {
if (!con.isClosed() && con != null) {
connstatus.setInUse(false);
connstatus.setLastUsed(System.currentTimeMillis());
USE_NUM = USE_NUM - 1;// 正在使用的连接数减少1
maxflag = false;// 设置状态字,没有取到连接的进程可以取连接了
} else {
databasepool.remove(i);
NUM = NUM - 1;
USE_NUM = USE_NUM - 1;// 正在使用的连接数减少1
maxflag = false;// 设置状态字,没有取到连接的进程可以取连接了
}
} catch (Exception e) {
System.out.println(e.toString());
}
}
}
}
/*
* 定时检查连接池的情况 该静态类为执行任务
*/
static class MyTask extends java.util.TimerTask {
public void run() {
ConnectionStatus connstatus = null;// 连接状态
Connection conn = null;// 连接
int topnum = NUM;// 定义循环的上限****重要****
for (int i = 0; i < topnum; i++) {
connstatus = (ConnectionStatus) databasepool.get(i);
conn = (Connection) connstatus.getConn();
try {
if (conn.isClosed() || conn == null)// 释放空连接
{
databasepool.remove(i);// 将空连接移出连接池
if (connstatus.getInUse()) // 如果显示连接正在使用
{
USE_NUM = USE_NUM - 1;// 使用的连接数增加1
}
NUM = NUM - 1;// 连接池减少1
i = i - 1;// 调整连接池下标,下标向前移动一位,避免检查遗漏*****非常注意********
maxflag = false;// 设置状态字,没有取到连接的进程可以取连接了
}
if (connstatus.getInUse()) // 如果连接在使用
{
if (System.currentTimeMillis()
- connstatus.getLastUsed() >= MAX_IDLE)// 强制回收超时连接
{
connstatus.setInUse(false);
connstatus.setLastUsed(System.currentTimeMillis());
USE_NUM = USE_NUM - 1;// 正在使用的连接数减少1
maxflag = false;// 设置状态字,没有取到连接的进程可以取连接了
}
}
} catch (Exception e) {
System.out.println(e.toString());
}
}
}
}
/*
* 将已经关闭的连接从连接池释放出去 将已经超时的连接强制回收到数据库连接池
*/
public synchronized void CheckConnection() {
ConnectionStatus connstatus = null;// 连接状态
Connection conn = null;// 连接
int topnum = NUM;// 定义循环的上限****重要****
for (int i = 0; i < topnum; i++) {
connstatus = (ConnectionStatus) databasepool.get(i);
conn = (Connection) connstatus.getConn();
try {
if (conn.isClosed() || conn == null)// 释放空连接
{
databasepool.remove(i);// 将空连接移出连接池
if (connstatus.getInUse()) // 如果连接正在使用
{
USE_NUM = USE_NUM - 1;// 使用的连接数增加1
}
NUM = NUM - 1;// 连接池减少1
i = i - 1;// 调整连接池下标,下标向前移动一位,避免检查遗漏*****非常注意********
maxflag = false;// 设置状态字,没有取到连接的进程可以取连接了
}
if (connstatus.getInUse()) // 如果连接在使用
{
if (System.currentTimeMillis() - connstatus.getLastUsed() >= MAX_IDLE)// 强制回收超时连接
{
connstatus.setInUse(false);
connstatus.setLastUsed(System.currentTimeMillis());
USE_NUM = USE_NUM - 1;// 使用的连接数减少1
maxflag = false;// 设置状态字,没有取到连接的进程可以取连接了
}
}
} catch (Exception e) {
System.out.println(e.toString());
}
}
}
/**
* 销毁方法 释放所有连接和定时器
*/
public void finalize() throws Throwable {
ConnectionStatus connstatus = null;
for (int i = NUM; i > 0; i--) {
connstatus = (ConnectionStatus) databasepool.get(i);
if (connstatus.getConn() != null) {
try {
connstatus.getConn().close();
} catch (Exception e) {
System.out.println(e.toString());
}
}
databasepool.remove(i);
}
NUM = 0;// 总连接
USE_NUM = 0;// 正在使用的连接
timer.cancel();// 取消定时器
}
}
- 1
- 2
前往页