-
数据库连接池(
DataSource
)
1
、概念
在
三层架构中,
DAO
层直接与数据库交互,首先要建立与数据库
的连接,如果采用下
图(
a
)所示,则
用户每次的请求都要创建连接,用完又关闭,而数据库连接的创建和关闭
需要消耗较大的
资源,因此实际开发中常采用图(
b
)所示,在应用程序启动时
创建一个包
含多个
Connection
对象的连接池,
DAO
层使用时直接从池子里取一个
Connection
对象,用
完后放回池子,
避免了重复创建关闭数据库连接造成的开销。
2
、数据库连接池原理
下面的代码模拟了数据库连接池的原理
(代码中的
J
DBCUtil
工具类见
《
MySQL
(
JDBC
)
》
)
,
池子里保持了
< br>10
个
Connection
对
象,并提供了
getConnection
和
< br>release
方法:
public
class
ConnectionPoolDemo {
//
连接
池实际上就是一个
List
private
static
List
pool
=
new
LinkedList
}
p>
static
{
//
加载连接池类时在池子中放入
10
个连接
for
(
int
i = 0;i < 10;i ++){
Connection conn;
try
{
conn =
JDBCUtil.
getConnection
();
pool
.add(conn);
}
catch
(Exception e) {
tackTrace();
}
}
}
//
从池子中取出一个连接
public
synchronized
Connection
getConnection(){
return
pool
.remove(0);
}
//
把连接还回池子中
public
static
void
release(Connection
conn){
pool
.add(conn);
}
3
、编写一个符合规范的连接池
p>
上节模拟数据库连接池原理的代码也实现了一个简单连接池,
但是不
符合规范
(
Sun
公司制
定)。编写一个符合规范的连接池需要实现
urce
接口。(
DataSource
接口
中
定义了两个重载的
getConnection
方法)
编程难点
☆:
p>
当用户使用完
Connection
,执行
()
时,
Connection
对象应保证将自
己还给连接池,而不要把
co
nn
关闭。之所由
Connection
对象保证将自己返回到
LinkedList
中,是因为
p>
DataSource
接口中并未定义上节例子中类似
release
的方法。所以必须改写
Connec
tion
中的
close
方法,使得用
户执行
()
时,将
Connectio
n
对象还给连接池。
解决方案
☆
:改写驱动程序中
Connection
类的
close
方法。
对已知类的某
些方法进行功能
上的改变,有以下几种编码方案(☆):
p>
1
)编写子类,覆写需要改变的方法。此处行不通,原因有:①
p>
程序中不知道继承哪个驱动
的
Connection
实现类
②
数据库驱动对
Connection
接口的实现类是
final
的,
不允许被继承。
2
)装饰(包装)设计模式(静态代理)
①
定义包装类:
MyConnection
,该类完成了对
tion<
/p>
类的包装。
关键词:保持被包装对象的
原有信息、对某个
/
某些方法进行改写。包装类的编写过程如下
:
/**
*
目前要包装的类是:
tion
*
@author
flyne
*/
//1
、编写一个类,实现与被包装类相同的接口。
public
class
MyConnection
implements
Connection {
p>
//2
、定义一个变量,引用被包装类的实例(保持被包装对象的原
有信息)
private
Connection
conn
;
private
List
pool
;
//close
< br>方法中需要用
//3
、在构造方法中传入被包装类的实例
public
MyConnection(Connection conn,List
this
.
conn
= conn;
this
.
pool
=
pool;
}
//4
、对于需要改写的方法,编写自己的代码即可
public
void
close()
throws
SQLException {
pool
.add(
conn
);
}
//5
、对于不需要改写的方法,调用被包装对象的对应方法
public
throws
SQLException {
return
conn
.unwrap(iface);
}
……
/
/
其他代码从略
}
②实现
DataSource
接口。
public
class
MyDataSource
implements
DataSource {
private
static
List
pool
=
new
LinkedList
static
{
try
{
for
(
int
i=0;i<10;i++){
}
Connection conn = JDBCUtil.
g
etConnection
();
//
创建的新连接
pool
.add(conn);
}
}
catch
(Exception e) {
tackTrace();
}
public
Connection
getConnection()
throws
SQLException {
if<
/p>
(
pool
.size()>0){
Connection conn =
pool
.remove(0);
MyConnection mconn =
new
MyConnection(conn,
pool
);
return
mconn;
}
else
{
throw
new
RuntimeException(
服务器忙
);
}
}
……
//
其他代码从略
}
3
)默认适配器
Connection
接口中有多个方法,
如果直接实现此
接口,
那么需要在实现类中实现所有的方法,
但往往可能只用到
接口中一个或者几个方法(如上面的
MyConnection
类),显然用这样的
实现类会造成资源的浪费,系统开销的加大。此时可以在中间引入一
个默认适配器。
①
默认适配器
默认适配器本身也是一个
包装类,但并没有对任何的方法进行改写:
public
class
ConnectionAdapter
implements
Connection {
private
Connection
conn
;
public
ConnectionAdapter(Connection conn){
this
.
conn
= conn;
}
public
throws
SQLException {
return
this
.unwrap(iface);
}
}
……
//
其他代码从略
②
MyConnection
类的改写,此时直接继承
ConnectionAdapter
,并改写
close()
方法即可。
public
class
MyConnection
extends
ConnectionAdapter {
private
Connection
conn
;
private
List
pool
;
public
MyConnection(Connection conn,List
super
(conn);
this
.
conn
= conn;
p>
this
.
pool
= pool;