关于自己实现的一个简易数据库连接池的一些问题

iamrf 2009-12-09 02:44:22
我用LinkedList实现了个简易的先进先出的队列来充当连接池,之前的一个用静态代理实现的版本中,拦截close()方法来实现调用close()方法将代理连接放入池中。在放入之前做个判断,如果List中没有这个连接时放入,如果有就不放,用来避免对同一个连接多次调用close()方法导致池中有多个相同连接。

但我之后用动态代理实现的版本中这个判断就不起作用了,假如对同一个连接调用了10次close()方法,则池中就会多出10个一模一样的链接。我是这样判断的
if (!connectionsPool.contains(conn)){
connectionsPool.addLast(conn);
}
请问这是为什么?是跟动态代理产生的类的某些特性有关么?


这个问题在高性能WEB开发有更详细的说明
http://topic.csdn.net/u/20091209/13/5dc8960f-79ad-47ba-9873-bd727f8691f4.html?16433
...全文
170 15 打赏 收藏 转发到动态 举报
AI 作业
写回复
用AI写文章
15 条回复
切换为时间正序
请发表友善的回复…
发表回复
iamrf 2009-12-10
  • 打赏
  • 举报
回复
[Quote=引用 13 楼 zhouzongjiu 的回复:]
不是代理的问题,是contains方法的问题
public void free(Connection conn) {
        if (!connectionsPool.contains(conn))
            connectionsPool.addLast(conn);
}
改为
public void free(Connection conn) {
    int i=0;
    for (i=0;i <connectionsPool.size();i++) {
        if (connectionsPool.get(i)==(conn)) {
        break;
        }
    }
    if (i>=connectionsPool.size()) {
    connectionsPool.addLast(conn);
    }
}

[/Quote]


昨天晚上回去看了看设计模式,也同意你的观点:应该是contains()方法的问题,而不是模式的问题
你这个方法我试了,不过有个细节得改动一下,改动如下:
		int i = 0;
for (i = 1; i <= connectionsPool.size(); i++) {
if (conn == connectionsPool.get(i-1)) {
break;
}
}
if (i > connectionsPool.size()) {
connectionsPool.addLast(conn);
}


这样就满足了,对同一个连接多次调用close()方法的问题就解决了。

但还有个问题,我看了看contains()方法的源代码,其内部也是把List中的元素一个一个拿出来然后跟参数(也就是需要对比的那个obj)进行equals(),而我没有覆写equals()方法,那就是调用根类Object的equals()方法。Object类的equals()方法也是(this == obj)用 == 来判断的啊~~判断它的hashCode是否相等。

按理来说内部实现机制和代码里写的 if (connectionsPool.get(i)==(conn)) 这句应该是一样的,但为什么现在的判断结果却不一样啊~~这点我很费解,不知道有没有人知道?
iamrf 2009-12-10
  • 打赏
  • 举报
回复
11楼给的连接池不好用啊~~这个连接池自己写的自己用还可以,因为好多方法是这个连接池自己的,并不符合客户端程序员的编程习惯。而且也存在很多潜在上的算法问题。

比如说释放连接只能是freeConnection()这个方法,但一般的用户可能就直接调用close()将其关闭了。或者以前写好的代码中就是调用close()方法来释放连接的。

如果用代理模式来做的话可以直接拦截close()方法,而用户根本就不需要更改原先已经写好的代码(把原先的close()方法全部更换为freeConnection()方法)

11楼应该拿的是一个数据库连接池教学用的示意性用例,也只是仅供看看~~不过还是很感谢拿出来分享。
zhouzongjiu 2009-12-10
  • 打赏
  • 举报
回复
不是代理的问题,是contains方法的问题
public void free(Connection conn) {
if (!connectionsPool.contains(conn))
connectionsPool.addLast(conn);
}
改为
public void free(Connection conn) {
int i=0;
for (i=0;i<connectionsPool.size();i++) {
if (connectionsPool.get(i)==(conn)) {
break;
}
}
if (i>=connectionsPool.size()) {
connectionsPool.addLast(conn);
}
}
java_running 2009-12-09
  • 打赏
  • 举报
回复
对比学习下....
java_running 2009-12-09
  • 打赏
  • 举报
回复

public class DBConnectionPool {
private int checkedOut; //
private Vector freeConnections = new Vector();
private int maxConn; // 最大的连接数
private int normalConn; // 正常连接数
private String password;
private String url;
private String user;
private static int num=0;//空闲的连接数
private static int numActive=0;//当前的连接数

public DBConnectionPool(String password, String url, String user,
int normalConn, int maxConn) { // 实例化 加载数据...
this.password = password;
this.url = url;
this.user = user;
this.maxConn = maxConn;
this.normalConn = normalConn;

for (int i = 0; i < normalConn; i++) { //初始normalConn个连接
Connection c = newConnection();
if (c != null)
{freeConnections.addElement(c);num++;}
}
}

// 释放不用的连接到连接池
public synchronized void freeConnection(Connection con) {
freeConnections.addElement(con);
num++;
checkedOut--;
numActive--;
notifyAll();
}


// 获取一个可用连接
public synchronized Connection getConnection() {
Connection con = null;

if (freeConnections.size() > 0) { //还有空闲的连接
num--;

con = (Connection) freeConnections.firstElement();
freeConnections.removeElementAt(0);
try {
if (con.isClosed()) {
System.out.println("从连接池删除一个无效连接");
con = getConnection();
}
}
catch (SQLException e) {
System.out.println("从连接池删除一个无效连接");
con = getConnection();
}
}

else if (maxConn == 0 || checkedOut < maxConn) { //没有空闲连接且当前连接小于最大允许值,最大值为0则不限制
con = newConnection();
}

if (con != null) { //当前连接数加1
checkedOut++;
}

numActive++;
return con;

}

// 获取一个连接,并加上等待时间限制,时间为毫秒
public synchronized Connection getConnection(long timeout) {
long startTime = new Date().getTime();
Connection con;
while ( (con = getConnection()) == null) {

try {
wait(timeout);
}
catch (InterruptedException e) {}

if ( (new Date().getTime() - startTime) >= timeout) {
return null; //超时返回
}
} //0
return con;
}

// 关闭所有连接
public synchronized void release() {
Enumeration allConnections = freeConnections.elements();
while (allConnections.hasMoreElements()) {
Connection con = (Connection) allConnections.nextElement();
try {
con.close();
num--;
}
catch (SQLException e) {
System.out.println("无法关闭连接池中的连接");
e.printStackTrace();
}
}
freeConnections.removeAllElements();
numActive=0;
}

// 创建一个新连接
private Connection newConnection() {
Connection con = null;
try {
if (user == null) { //用户,密码都为空
con = DriverManager.getConnection(url);
}
else {
con = DriverManager.getConnection(url, user, password);
}
//System.out.println("连接池创建一个新的连接");
}
catch (SQLException e) {
System.out.println("无法创建这个URL的连接" + url);
e.printStackTrace();
return null;
}
return con;
}


// 返回当前空闲连接数
public int getnum()
{
return num;
}


// 返回当前连接数
public int getnumActive()
{
return numActive;
}


}
iamrf 2009-12-09
  • 打赏
  • 举报
回复
[Quote=引用 7 楼 zhouzongjiu 的回复:]
this.myDataSource.free(this.warpedConnection);
改为
this.myDataSource.free((Connection)proxy);
试试
还有就是照你的想法应该把
return method.invoke(this.realConnection, args);
放到else中吧。

[/Quote]

invoke方法中的proxy实际就是this.warpedConnection
所以两种写法都一样,return放else中一个样,还是对同一个连接调用多次close()方法池内会多出好多连接。
zjhlht 2009-12-09
  • 打赏
  • 举报
回复
关注一下~~~~
iamrf 2009-12-09
  • 打赏
  • 举报
回复
判断那里应该不会有问题,因为往连接池中放的时候应该放代理连接而不是真正的连接,如果让真正连接进去,那再次取出使用后,一调用close()方法就把链接真正关闭了。

我觉得是不是动态代理的机制引起的,因为它毕竟是内存中一个虚拟出来的类,而不是真正的磁盘上的一个class文件。

刚接触动态Proxy没多久,好多都不清楚~~还请高手传授点使用经验
zhouzongjiu 2009-12-09
  • 打赏
  • 举报
回复
this.myDataSource.free(this.warpedConnection);
改为
this.myDataSource.free((Connection)proxy);
试试
还有就是照你的想法应该把
return method.invoke(this.realConnection, args);
放到else中吧。
panhaichun 2009-12-09
  • 打赏
  • 举报
回复
不是这里问题,说错了,再看看
chenliuyang 2009-12-09
  • 打赏
  • 举报
回复
你应该放进去的是代理连接, 比较时是跟原来的连接比,
panhaichun 2009-12-09
  • 打赏
  • 举报
回复
这句话

if (this.currentCount < this.maxUseCount)
this.myDataSource.free(this.warpedConnection);

应该是
if (this.currentCount < this.maxUseCount)
this.myDataSource.free(this.realConnection);


iamrf 2009-12-09
  • 打赏
  • 举报
回复
这个是MyConnectionHandler类


public class MyConnectionHandler implements InvocationHandler {

private int currentCount = 0;
private int maxUseCount = 3;

private MyDataSource2 myDataSource;
private Connection realConnection;
private Connection warpedConnection;

MyConnectionHandler(MyDataSource2 myDataSource) {
this.myDataSource = myDataSource;
}

Connection bind(Connection realConnection) {
this.realConnection = realConnection;
this.warpedConnection = (Connection) Proxy.newProxyInstance(this
.getClass().getClassLoader(), new Class[] { Connection.class },
this);
System.out.println("--" + warpedConnection.getClass().getName());
return warpedConnection;
}

@Override
public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable {
if ("close".equals(method.getName())) {
this.currentCount++;
if (this.currentCount < this.maxUseCount)
this.myDataSource.free(this.warpedConnection);
else {
this.realConnection.close();
this.myDataSource.setCurrentCount((this.myDataSource
.getCurrentCount() - 1) < 0 ? 0 : (this.myDataSource
.getCurrentCount() - 1));
}
}
return method.invoke(this.realConnection, args);
}

}
iamrf 2009-12-09
  • 打赏
  • 举报
回复
这个是MyDataSource2类

public final class MyDataSource2 {

private String url = "jdbc:mysql://localhost:3306/shopping";
private String user = "root";
private String password = "JD-ESMS";

private static int initCount = 4;
private static int maxCount = 6;
private int currentCount = 0;

private static MyDataSource2 myDataSource = new MyDataSource2();
private LinkedList<Connection> connectionsPool = new LinkedList<Connection>();

private MyDataSource2() {
try {
for (int i = 0; i < initCount; i++) {
this.connectionsPool.addLast(this.createConnection());
this.currentCount++;
}
} catch (SQLException e) {
System.err.println("连接池创建失败:");
e.printStackTrace();
throw new ExceptionInInitializerError(e);
}
}

public static MyDataSource2 getInstance() {
return myDataSource;
}

public Connection getConnection() throws SQLException {
synchronized (connectionsPool) {
System.out.print("池内空闲连接数:" + this.connectionsPool.size() + "\t"
+ "当前连接数:" + currentCount + "\t");
if (this.connectionsPool.size() > 0) {
return this.connectionsPool.removeFirst();
}
if (this.currentCount < maxCount) {
currentCount++;
return this.createConnection();
}
throw new SQLException("已达到数据库最大连接数");
}
}

public void free(Connection conn) {
if (!connectionsPool.contains(conn))
connectionsPool.addLast(conn);
}

private Connection createConnection() throws SQLException {
Connection realConnection = DriverManager.getConnection(url, user, password);
MyConnectionHandler proxy = new MyConnectionHandler(this);
return proxy.bind(realConnection);
}

public int getCurrentCount() {
return currentCount;
}

public void setCurrentCount(int currentCount) {
this.currentCount = currentCount;
}
}
panhaichun 2009-12-09
  • 打赏
  • 举报
回复
无代码无真相
Spring4GWT GWT Spring 使得在 Spring 框架下构造 GWT 应用变得很简单,提供一个易于理解的依赖注入和RPC机制。 Java扫雷游戏 JVMine JVMine用Applets开发的扫雷游戏,可在线玩。 public class JVMine extends java.applet.Applet 简单实现!~ 网页表格组件 GWT Advanced Table GWT Advanced Table 是一个基于 GWT 框架的网页表格组件,可实现分页数据显示、数据排序和过滤等功能! Google Tag Library 该标记库和 Google 有关。使用该标记库,利用 Google 为你的网站提供网站查询,并且可以直接在你的网页里面显示搜查的结果。 github-java-api github-java-api 是 Github 网站 API 的 Java 语言版本。 java缓存工具 SimpleCache SimpleCache 是一个简单易用的java缓存工具,用来简化缓存代码的编写,让你摆脱单调乏味的重复工作!1. 完全透明的缓存支持,对业务代码零侵入 2. 支持使用Redis和Memcached作为后端缓存。3. 支持缓存数据分区规则的定义 4. 使用redis作缓存时,支持list类型的高级数据结构,更适合论坛帖子列表这种类型的数据 5. 支持混合使用redis缓存和memcached缓存。可以将列表数据缓存到redis中,其他kv结构数据继续缓存到memcached 6. 支持redis的主从集群,可以做读写分离。缓存读取自redis的slave节点,写入到redis的master节点。 Java对象的SQL接口 JoSQL JoSQL(SQLforJavaObjects)为Java开发者提供运用SQL语句来操作Java对象集的能力.利用JoSQL可以像操作数据库中的数据一样对任何Java对象集进行查询,排序,分组。 搜索自动提示 Autotips AutoTips是为解决应用系统对于【自动提示】的需要(如:Google搜索), 而开发的架构无关的公共控件, 以满足该类需求可以通过快速配置来开发。AutoTips基于搜索引擎Apache Lucene实现。AutoTips提供统一UI。 WAP浏览器 j2wap j2wap 是一个基于Java的WAP浏览器,目前处于BETA测试阶段。它支持WAP 1.2规范,除了WTLS 和WBMP。 Java注册表操作类 jared jared是一个用来操作Windows注册表的 Java 类库,你可以用来对注册表信息进行读写。 GIF动画制作工具 GiftedMotion GiftedMotion是一个很小的,免费而且易于使用图像互换格式动画是能够设计一个有趣的动画了一系列的数字图像。使用简便和直截了当,用户只需要加载的图片和调整帧您想要的,如位置,时间显示和处理方法前帧。 Java的PList类库 Blister Blister是一个用于操作苹果二进制PList文件格式的Java开源类库(可用于发送数据给iOS应用程序)。 重复文件检查工具 FindDup.tar FindDup 是一个简单易用的工具,用来检查计算机上重复的文件。 OpenID的Java客户端 JOpenID JOpenID是一个轻量级的OpenID 2.0 Java客户端,仅50KB+(含源代码),允许任何Web网站通过OpenID支持用户直接登录而无需注册,例如Google Account或Yahoo Account。 JActor的文件持久化组件 JFile JFile 是 JActor 的文件持久化组件,以及一个高吞吐量的可靠事务日志组件。 Google地图JSP标签库 利用Google:maps JSP标签库就能够在你的Web站点上实现GoogleMaps的所有功能而且不需要javascript或AJAX编程。它还能够与JSTL相结合生成数据库驱动的动态Maps。 OAuth 实现框架 Agorava Agorava 是一个实现了 OAuth 1.0a 和 OAuth 2.0 的框架,提供了简单的方式通过社交媒体进行身份认证的功能。 Eclipse的JavaScript插件 JSEditor JSEditor 是 Eclipse 下编辑 JavaScript 源码的插件,提供语法高亮以及一些通用的面向对象方法。 Java数据库连接池 BoneCP BoneCP 是一个高性能的开源java数据库连接池实现库。它的设计初衷就是为了提高数据库连接池的性能,根据某些测试数据发现,BoneCP是最快的连接池。BoneCP很小,只有四十几K
Spring4GWT GWT Spring 使得在 Spring 框架下构造 GWT 应用变得很简单,提供一个易于理解的依赖注入和RPC机制。 Java扫雷游戏 JVMine JVMine用Applets开发的扫雷游戏,可在线玩。 public class JVMine extends java.applet.Applet 简单实现!~ 网页表格组件 GWT Advanced Table GWT Advanced Table 是一个基于 GWT 框架的网页表格组件,可实现分页数据显示、数据排序和过滤等功能! Google Tag Library 该标记库和 Google 有关。使用该标记库,利用 Google 为你的网站提供网站查询,并且可以直接在你的网页里面显示搜查的结果。 github-java-api github-java-api 是 Github 网站 API 的 Java 语言版本。 java缓存工具 SimpleCache SimpleCache 是一个简单易用的java缓存工具,用来简化缓存代码的编写,让你摆脱单调乏味的重复工作!1. 完全透明的缓存支持,对业务代码零侵入 2. 支持使用Redis和Memcached作为后端缓存。3. 支持缓存数据分区规则的定义 4. 使用redis作缓存时,支持list类型的高级数据结构,更适合论坛帖子列表这种类型的数据 5. 支持混合使用redis缓存和memcached缓存。可以将列表数据缓存到redis中,其他kv结构数据继续缓存到memcached 6. 支持redis的主从集群,可以做读写分离。缓存读取自redis的slave节点,写入到redis的master节点。 Java对象的SQL接口 JoSQL JoSQL(SQLforJavaObjects)为Java开发者提供运用SQL语句来操作Java对象集的能力.利用JoSQL可以像操作数据库中的数据一样对任何Java对象集进行查询,排序,分组。 搜索自动提示 Autotips AutoTips是为解决应用系统对于【自动提示】的需要(如:Google搜索), 而开发的架构无关的公共控件, 以满足该类需求可以通过快速配置来开发。AutoTips基于搜索引擎Apache Lucene实现。AutoTips提供统一UI。 WAP浏览器 j2wap j2wap 是一个基于Java的WAP浏览器,目前处于BETA测试阶段。它支持WAP 1.2规范,除了WTLS 和WBMP。 Java注册表操作类 jared jared是一个用来操作Windows注册表的 Java 类库,你可以用来对注册表信息进行读写。 GIF动画制作工具 GiftedMotion GiftedMotion是一个很小的,免费而且易于使用图像互换格式动画是能够设计一个有趣的动画了一系列的数字图像。使用简便和直截了当,用户只需要加载的图片和调整帧您想要的,如位置,时间显示和处理方法前帧。 Java的PList类库 Blister Blister是一个用于操作苹果二进制PList文件格式的Java开源类库(可用于发送数据给iOS应用程序)。 重复文件检查工具 FindDup.tar FindDup 是一个简单易用的工具,用来检查计算机上重复的文件。 OpenID的Java客户端 JOpenID JOpenID是一个轻量级的OpenID 2.0 Java客户端,仅50KB+(含源代码),允许任何Web网站通过OpenID支持用户直接登录而无需注册,例如Google Account或Yahoo Account。 JActor的文件持久化组件 JFile JFile 是 JActor 的文件持久化组件,以及一个高吞吐量的可靠事务日志组件。 Google地图JSP标签库 利用Google:maps JSP标签库就能够在你的Web站点上实现GoogleMaps的所有功能而且不需要javascript或AJAX编程。它还能够与JSTL相结合生成数据库驱动的动态Maps。 OAuth 实现框架 Agorava Agorava 是一个实现了 OAuth 1.0a 和 OAuth 2.0 的框架,提供了简单的方式通过社交媒体进行身份认证的功能。 Eclipse的JavaScript插件 JSEditor JSEditor 是 Eclipse 下编辑 JavaScript 源码的插件,提供语法高亮以及一些通用的面向对象方法。 Java数据库连接池 BoneCP BoneCP 是一个高性能的开源java数据库连接池实现库。它的设计初衷就是为了提高数据库连接池的性能,根据某些测试数据发现,BoneCP是最快的连接池。BoneCP很小,只有四十几K

81,122

社区成员

发帖
与我相关
我的任务
社区描述
Java Web 开发
社区管理员
  • Web 开发社区
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧