📄 dbconnectionmanager.java
字号:
package com.ntsky.pool;
import java.io.*;
import java.sql.*;
import java.util.*;
import com.ntsky.common.*;
/**
* <p>Title: NTsky新闻发布v1.0正式版</p>
* <p>Description: 数据库连接池</p>
* <p>Copyright: Copyright (c) 2003</p>
* <p>Company: NTsky</p>
* @authory 姚君林
* @version 1.0
*/
public class DBConnectionManager {
static private DBConnectionManager instance; //唯一实例的引用
static private int clients; //客户端的连接数目
private Vector drivers = new Vector();
private Hashtable pools = new Hashtable(); //创建一个Hashtable对象
class DBConnectionPool { //定义一个DBConnectionPool类[如果DBConnectionManager要访问DBConnectionPool必须创建DBConnectionPool的对象]
private int checkedOut; //判断是否还有可用的连接
private Vector freeConnections = new Vector();//创建一个freeConnections的数组
private int maxConn; //最大连接数
private String name; //数据库连接池名
private String user; //访问数据库用户名
private String password; //访问数据库密码
private String URL; //数据库地址
private PrintWriter log; //日志
/**
* 配置文件各项参数
* @param name
* @param url
* @param user
* @param password
* @param maxConn
*/
public DBConnectionPool(String name, String url, String user,
String password, int maxConn) {
/**
*配置文件
*/
this.name = name; //poolname 连接池名
this.URL = url; //地址
this.user = user; //用户名
this.password = password; //密码
this.maxConn = maxConn; //最大的连接数
//写日志
this.log = new PrintWriter(System.err);
Debug.writeLog("poolname" + this.name); //7、"poolname" + Connection
Debug.writeLog("URL: " + this.URL); //8、jdbc:mysql://127.0.0.1:3306/nt
Debug.writeLog("user: " + this.user); //9、user: skyyjl
Debug.writeLog("password: " + this.password); //10、password: abc
Debug.writeLog("maxConn: " + this.maxConn); //11、maxConn: 100
}
/**
* 把空闲的连接登记到连接池由的freeConnection()方法实现
* 它的参数为返回给连接池的连接对象。该对象被加入到freeConnections向量的末尾,然后减少已使用连接计数。
* 调用notifyAll()是为了通知其它正在等待可用连接的线程。
* @param Conn
*/
public synchronized void freeConnection(Connection Conn) {
freeConnections.addElement(Conn);
checkedOut--;
notifyAll();
}
/**
* 如连接池中存在可用连接,则直接返回,否则创建新的连接并返回。
* 如果没有可用连接且已有连接总数等于最大限制数,第一个方法将直接返回null,
* 而第二个方法将等待直到有可用连接为止
* 所有的可用连接对象均登记在名为freeConnections的向量(Vector)中。
* 如果向量中有多于一个的连接,getConnection()总是选取第一个。
* 由于新的可用连接总是从尾部加入向量,从而使得数据库连接由于长时间闲置而被关闭的风险减低到最小程度。
*
* @return Connection
*/
public synchronized Connection getConnection() {
Connection con = null;
if (freeConnections.size() > 0) { //获取向量中第一个可用连接
con = (Connection) freeConnections.firstElement(); //创建第一个connection,并用设置为Connection
freeConnections.removeElementAt(0);
try {
/**
* 第一个getConnection()在返回可用连接给客户程序之前,调用了isClosed()方法验证连接仍旧有效。
* 如果该连接被关闭或触发异常,getConnection()递归地调用自己以尝试获取另外的可用连接。
*/
if (con.isClosed()) { //判断连接是否关闭
Debug.writeLog("从连接池" + name + "删除一个无效连接");
con = getConnection(); //递归调用自己,尝试再次获取可用连接
}
}
catch (SQLException e) {
Debug.writeLog("从连接池" + name + "删除一个无效连接"); // 递归调用自己,尝试再次获取可用连接
con = getConnection();
}
}
/**
* 如果在向量freeConnections中不存在任何可用连接,getConnection()方法检查是否已经指定最大连接数限制。
* 如已经指定,则检查当前连接数是否已经到达极限。此处maxConn为0表示没有限制。
* 如果没有指定最大连接数限制或当前连接数小于该值,该方法尝试创建新的连接。
* 如创建成功,则增加已使用连接的计数(checkout)并返回,否则返回空值。
*/
else if (maxConn == 0 || checkedOut < maxConn) {
con = newConnection(); //创建连接(数量由maxConn决定)
}
if (con != null) { //如果conn(连接数)不为空,判断就加
checkedOut++;
}
if (con == null) { //如果为空就将con为空写入日志
Debug.writeLog(
"DBConnectionPool getConnection(), The Returned Con is null");
}
return con; //返回连接
}
/**
* 用一个以毫秒为单位的时间参数,该参数表示客户程序能够等待的最长时间。
* 建立连接的具体操作仍旧由第一个getConnection()方法实现。
* 参见前一个getConnection()方法.
* @param timeout 以毫秒计的等待时间限制
*/
public synchronized Connection getConnection(long timeout) {
long startTime = new java.util.Date().getTime(); //连接的初始时间
Connection con;
/**
* 在while循环中尝试获得一个连接。如果失败,则以给定的时间值为参数调用wait()。
* wait()的返回可能是由于其它线程调用notify()或notifyAll(),也可能是由于预定时间已到。
* 为找出wait()返回的真正原因,程序用当前时间减开始时间(startTime),
* 如差值大于预定时间则返回空值,否则再次调用getConnection()。
*/
while ( (con = getConnection()) == null) {
try {
wait(timeout);
}
catch (InterruptedException e) {
}
if ( (new java.util.Date().getTime() - startTime) >= timeout) { //wait()返回的原因是超时
return null; //连接超时,释放掉连接
}
}
return con; //返回连接
}
private void log(String msg) {
log.println(new java.util.Date() + ": " + msg);
}
/**
* 将文本信息与异常写入日志文件
*/
private void log(Throwable e, String msg) {
log.println(new java.util.Date() + ": " + msg);
e.printStackTrace(log);
}
/**
* 创建新连接由newConnection()方法实现。
* 创建过程与是否已经指定数据库帐号、密码有关。
* JDBC的DriverManager类提供多个getConnection()方法,这些方法要用到JDBC URL与其它一些参数,如用户帐号和密码等。
* DriverManager将使用指定的JDBC URL确定适合于目标数据库的驱动程序及建立连接。
*/
private Connection newConnection() {
Connection con = null;
try {
if (user == null) {
con = DriverManager.getConnection(URL); //保持数据库连接加载数据库驱动程序
}
else {
con = DriverManager.getConnection(URL, user, password);
}
Debug.writeLog("连接池" + name + "创建一个新的连接"); //21、如果有用户连接就写入日志说明有用户创建了连接
}
catch (SQLException e) {
Debug.writeLog("无法创建下列URL的连接: " + URL);
e.printStackTrace(System.out);
return null;
}
if (con == null) {
Debug.writeLog(
"DBConnectionPool newConnection(), The Returned Con is null");
}
return con;
}
/**
* 实现的release()方法供DBConnectionManager调用。
* 该方法遍历freeConnections向量并关闭所有连接,然后从向量中删除这些连接。
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -