1
package
ConnectionPool;
2
/** */
/**
3
此内部类定义了一个连接池。它能够根据要求创建新连接,直到预定的最大连接数为止。在返回连接给客户程序之前,它能够
4
验证连接的有效性。此类提供以下功能:
5
1.从连接池获取(或创建)可用连接
6
2.把连接返回给连接池
7
3.在系统关闭时释放所有资源,关闭所有连接
8
4.处理无效连接(原来登记为可用的连接,由于某种原因不再可用,如超时,通讯问题)
9
5.限制连接池中的连接总数不超过某个预定值
10
*/
11
import
java.io.
*
;
12
import
java.sql.
*
;
13
import
java.util.
*
;
14
import
java.util.Date;
15
16
class
DBConnectionPool
17
{
18
private
int
checkedOut;
19
private
PrintWriter logPrint;
20
private
Vector freeConnections
=
new
Vector();
21
private
int
maxConn;
22
private
String name;
23
private
String password;
24
private
String URL;
25
private
String user;
26
27
/** */
/**
28
创建新的连接池
29
*
@param
name 连接池名字
30
*
@param
URL 数据库的JDBC URL
31
*
@param
user 数据库帐号,或null
32
*
@param
password 密码,或null
33
*
@param
maxConn 此连接池允许建立的最大连接数
34
*/
35
public
DBConnectionPool(String name, String URL, String user, String password,
int
maxConn)
{
36
this
.name
=
name;
37
this
.URL
=
URL;
38
this
.user
=
user;
39
this
.password
=
password;
40
this
.maxConn
=
maxConn;
41
InputStream is
=
getClass().getResourceAsStream(
"
/db.properties
"
);
42
Properties dbProps
=
new
Properties();
43
try
{
44
dbProps.load(is);
45
}
46
catch
(Exception e)
{
47
System.err.println(
"
不能读取属性文件.
"
+
"
请确保db.properties在CLASSPATH指定的路径中
"
);
48
return
;
49
}
50
String logFile
=
dbProps.getProperty(
"
Poollogfile
"
,
"
DBConnectionPool.log
"
);
51
try
{
52
logPrint
=
new
PrintWriter(
new
FileWriter(logFile,
true
),
true
);
53
}
54
catch
(IOException e)
{
55
System.err.println(
"
无法打开日志文件:
"
+
logFile);
56
logPrint
=
new
PrintWriter(System.err);
57
}
58
}
59
60
61
/** */
/**
62
将不再使用的连接返回给连接池
63
*
@param
con 客户程序释放的连接
64
*/
65
public
synchronized
void
freeConnection(Connection con)
{
66
freeConnections.addElement(con);
67
checkedOut
--
;
68
notifyAll();
69
}
70
71
72
/** */
/**
73
从连接池获得一个可用连接,如没有空闲的连接且当前连接数小于最大连接数,则创建新连接,
74
如原来登记为可用的连接不再有效,则从向量删除之,然后递归调用自己以尝试新的可用连接
75
*/
76
public
synchronized
Connection getConnection()
{
77
Connection con
=
null
;
78
if
(freeConnections.size()
>
0
)
{
//
获取向量中第一个可用连接
79
con
=
(Connection)freeConnections.firstElement();
80
freeConnections.removeElementAt(
0
);
81
try
{
82
if
(con.isClosed())
{
83
log(
"
从连接池
"
+
name
+
"
删除一个无效连接
"
);
84
con
=
getConnection();
85
}
86
}
87
catch
(SQLException e)
{
88
log(
"
从连接池
"
+
name
+
"
删除一个无效连接
"
);
89
con
=
getConnection();
90
}
91
}
92
else
if
(maxConn
==
0
||
checkedOut
<
maxConn)
{
93
con
=
newConnection();
94
}
95
if
(con
!=
null
)
{
96
checkedOut
++
;
97
}
98
return
con;
99
}
100
101
102
/** */
/**
103
从连接池获取可用连接,可以指定客户程序能够等待的最长时间
104
*
@param
timeout 以毫秒计的等待时间限制
105
*/
106
public
synchronized
Connection getConnection(
long
timeout)
{
107
long
startTime
=
new
Date().getTime();
108
Connection con;
109
while
((con
=
getConnection())
==
null
)
{
110
try
{
111
wait(timeout);
112
}
113
catch
(InterruptedException e)
{}
114
115
if
((
new
Date().getTime()
-
startTime)
>=
timeout)
{
116
return
null
;
117
}
118
}
119
return
con;
120
}
121
122
123
/** */
/**
124
关闭所有连接
125
*/
126
public
synchronized
void
release()
{
127
Enumeration allConnections
=
freeConnections.elements();
128
while
(allConnections.hasMoreElements())
{
129
Connection con
=
(Connection)allConnections.nextElement();
130
try
{
131
con.close();
132
log(
"
关闭连接池
"
+
name
+
"
中的一个连接
"
);
133
}
134
catch
(SQLException e)
{
135
log(e,
"
无法关闭连接池
"
+
name
+
"
中的连接
"
);
136
}
137
}
138
freeConnections.removeAllElements();
139
}
140
141
142
/** */
/**
143
创建新的连接
144
*/
145
private
Connection newConnection()
{
146
Connection con
=
null
;
147
try
{
148
if
(user
==
null
)
{
149
con
=
DriverManager.getConnection(URL);
150
}
151
else
{
152
con
=
DriverManager.getConnection(URL, user, password);
153
}
154
log(
"
连接池
"
+
name
+
"
创建一个新的连接
"
);
155
}
156
catch
(SQLException e)
{
157
log(e,
"
无法创建下列URL的连接
"
+
URL);
158
return
null
;
159
}
160
return
con;
161
}
162
163
164
/** */
/**
165
将文本信息写入日志文件
166
缺省为packaged
167
*/
168
void
log(String msg)
{
169
logPrint.println(
new
Date()
+
"
:
"
+
msg);
170
}
171
172
173
/** */
/**
174
将文本信息与异常写入日志文件
175
*/
176
void
log(Throwable e, String msg)
{
177
logPrint.println(
new
Date()
+
"
:
"
+
msg);
178
e.printStackTrace(logPrint);
179
}
180
}
1
package
ConnectionPool;
2
3
/**/
/*
此类用于管理多个连接池对象,它支持对一个或多个由属性文件定义的数据库连接池的访问,客户程序可以调用getInstance()方法访问本类的唯一实例。它提供以下功能:
4
1.装载和注册JDBC驱动程序
5
2.根据在属性文件中定义的属性创建连接池对象
6
3.实现连接池名字与其实例之间的映射
7
4.跟踪客户程序对连接池的引用,保证在最后一个客户程序结束时安全地关闭所有连接池
8
*/
9
10
import
java.io.
*
;
11
import
java.sql.
*
;
12
import
java.util.
*
;
13
//
import com.supersoftintl.intranet.common.DBConnectionPool;
14
//
import java.util.Date;
15
/** */
/**
16
* 管理类DBConnectionManager支持对一个或多个由属性文件定义的数据库连接
17
* 池的访问.客户程序可以调用getInstance()方法访问本类的唯一实例.
18
*/
19
public
class
DBConnectionManager
{
20
static
private
DBConnectionManager instance;
/**/
/*
唯一实例
*/
21
static
private
int
clients;
22
/**/
/*
该计数代表引用DBConnectionManager唯一实例的客户程序总数,
23
它将被用于控制连接池的关闭操作
*/
24
25
static
private
String DEFAULTCONNECTIONPOOL
=
"
ConnectionPool
"
;
26
private
Vector drivers
=
new
Vector();
27
private
PrintWriter logPrint;
28
private
Hashtable pools
=
new
Hashtable();
29
30
/** */
/**
31
返回唯一实例。如果是第一次调用此方法,则创建实例
32
*/
33
static
synchronized
public
DBConnectionManager getInstance()
{
34
if
(instance
==
null
)
{
35
instance
=
new
DBConnectionManager();
36
}
37
clients
++
;
38
return
instance;
39
}
40
41
42
/** */
/**
43
建构函数私有以防止其它对象创建本类实例
44
*/
45
public
DBConnectionManager()
{
46
init();
47
}
48
49
50
/** */
/**
Added by leo on 2001-5-23
51
使用默认的连接池名,创建并返回新连接
52
*
53
*
@return
Connection 可用连接或null
54
*/
55
public
Connection getConnection()
{
56
return
getConnection(DEFAULTCONNECTIONPOOL);
57
}
58
59
60
/** */
/**
61
获得一个可用的(空闲的)连接.如果没有可用连接,且已有连接数小于最大连接数
62
限制,则创建并返回新连接
63
*
64
*
@param
name 在属性文件中定义的连接池名字
65
*
@return
Connection 可用连接或null
66
*/
67
public
Connection getConnection(String name)
{
68
DBConnectionPool pool
=
(DBConnectionPool)pools.get(name);
69
if
(pool
!=
null
)
{
70
return
pool.getConnection();
71
}
72
return
null
;
73
}
74
75
76
/** */
/**
77
获得一个可用连接.若没有可用连接,且已有连接数小于最大连接数限制,
78
则创建并返回新连接.否则,在指定的时间内等待其它线程释放连接.
79
*
80
*
@param
name 连接池名字
81
*
@param
time 以毫秒计的等待时间
82
*
@return
Connection 可用连接或null
83
*/
84
public
Connection getConnection(String name,
long
time)
{
85
DBConnectionPool pool
=
(DBConnectionPool)pools.get(name);
86
if
(pool
!=
null
)
{
87
return
pool.getConnection(time);
88
}
89
return
null
;
90
}
91
92
93
/** */
/**
Added by leo on 2001-5-23
94
将连接对象返回给默认的连接池
95
*
96
*
@param
con 连接对象
97
*/
98
public
void
freeConnection(Connection con)
{
99
String name
=
DEFAULTCONNECTIONPOOL;
100
freeConnection(name,con);
101
}
102
103
104
/** */
/**
105
将连接对象返回给由名字指定的连接池
106
*
107
*
@param
name 在属性文件中定义的连接池名字
108
*
@param
con 连接对象
109
*/
110
public
void
freeConnection(String name, Connection con)
{
111
DBConnectionPool pool
=
(DBConnectionPool)pools.get(name);
112
if
(pool
!=
null
)
{
113
pool.freeConnection(con);
114
}
115
}
116
117
118
/** */
/**
119
关闭所有连接,撤销驱动程序的注册
120
*/
121
public
synchronized
void
release()
{
//
等待直到最后一个客户程序调用
122
if
(
--
clients
!=
0
)
{
123
return
;
124
}
125
Enumeration allPools
=
pools.elements();
126
while
(allPools.hasMoreElements())
{
127
DBConnectionPool pool
=
(DBConnectionPool)allPools.nextElement();
128
pool.release();
129
}
130
Enumeration allDrivers
=
drivers.elements();
131
while
(allDrivers.hasMoreElements())
{
132
Driver driver
=
(Driver)allDrivers.nextElement();
133
try
{
134
DriverManager.deregisterDriver(driver);
135
log(
"
撤消JDBC驱动程序
"
+
driver.getClass().getName()
+
"
的注册
"
);
136
}
137
catch
(SQLException e)
{
138
log(e,
"
无法撤消下列JDBC驱动程序的注册
"
+
driver.getClass().getName());
139
}
140
}
141
}
142
143
144
/** */
/**
145
根据指定属性创建连接池实例.
146
*
147
*
@param
props 连接池属性
148
*/
149
private
void
createPools(Properties props)
{
150
Enumeration propNames
=
props.propertyNames();
151
while
(propNames.hasMoreElements())
{
152
String name
=
(String)propNames.nextElement();
153
if
(name.endsWith(
"
.url
"
))
{
154
String poolName
=
name.substring(
0
, name.lastIndexOf(
"
.
"
));
155
String url
=
props.getProperty(poolName
+
"
.url
"
);
156
if
(url
==
null
)
{
157
log(
"
没有为连接池
"
+
poolName
+
"
指定URL
"
);
158
continue
;
159
}
160
String user
=
props.getProperty(poolName
+
"
.user
"
);
161
String password
=
props.getProperty(poolName
+
"
.password
"
);
162
String maxconn
=
props.getProperty(poolName
+
"
.maxconn
"
,
"
0
"
);
163
int
max;
164
try
{
165
max
=
Integer.valueOf(maxconn).intvalue();
166
}
167
catch
(NumberformatException e)
{
168
log(
"
错误的最大连接数限制:
"
+
maxconn
+
"
.连接池:
"
+
poolName);
169
log(
"
自动改变设置为0--即无限制
"
);
170
max
=
0
;
171
}
172
DBConnectionPool pool
=
new
DBConnectionPool(poolName, url, user, password, max);
173
pools.put(poolName, pool);
174
log(
"
成功创建连接池
"
+
poolName);
175
}
176
}
177
}
178
179
180
/** */
/**
181
读取属性完成初始化
182
*/
183
private
void
init()
{
184
InputStream is
=
getClass().getResourceAsStream(
"
/db.properties
"
);
185
Properties dbProps
=
new
Properties();
186
try
{
187
dbProps.load(is);
188
}
189
catch
(Exception e)
{
190
System.err.println(
"
不能读取属性文件.
"
+
"
请确保db.properties在CLASSPATH指定的路径中
"
);
191
return
;
192
}
193
String logFile
=
dbProps.getProperty(
"
Managerlogfile
"
,
"
DBConnectionManager.log
"
);
194
try
{
195
logPrint
=
new
PrintWriter(
new
FileWriter(logFile,
true
),
true
);
196
}
197
catch
(IOException e)
{
198
System.err.println(
"
无法打开日志文件:
"
+
logFile);
199
logPrint
=
new
PrintWriter(System.err);
200
}
201
loadDrivers(dbProps);
202
createPools(dbProps);
203
}
204
205
206
/** */
/**
207
装载和注册所有JDBC驱动程序
208
*
209
*
@param
props 属性
210
*/
211
private
void
loadDrivers(Properties props)
{
212
String driverClasses
=
props.getProperty(
"
drivers
"
);
213
StringTokenizer st
=
new
StringTokenizer(driverClasses);
214
while
(st.hasMoreElements())
{
215
String driverClassName
=
st.nextToken().trim();
216
try
{
217
Driver driver
=
(Driver)Class.forName(driverClassName).newInstance();
218
DriverManager.registerDriver(driver);
219
drivers.addElement(driver);
220
log(
"
成功JDBC注册驱动程序
"
+
driverClassName);
221
}
222
catch
(Exception e)
{
223
log(
"
无法注册JDBC驱动程序;
"
+
driverClassName
+
"
,错误:
"
+
e);
224
}
225
}
226
}
227
228
229
/** */
/**
230
将文本信息写入日志文件
231
缺省为packaged
232
*/
233
void
log(String msg)
{
234
logPrint.println(
new
java.util.Date()
+
"
:
"
+
msg);
235
}
236
237
238
/** */
/**
239
将文本信息与异常写入日志文件
240
*/
241
void
log(Throwable e, String msg)
{
242
logPrint.println(
new
java.util.Date()
+
"
:
"
+
msg);
243
e.printStackTrace(logPrint);
244
}
245
}
posted on 2006-06-29 14:44
kelven 阅读(2173)
评论(0) 编辑 收藏 所属分类:
java