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

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
...全文
162 15 打赏 收藏 转发到动态 举报
写回复
用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
  • 打赏
  • 举报
回复
无代码无真相

81,092

社区成员

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

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