解惑

解己之惑,解人之惑

完成轮子的第三个部分-连接池

其实也不是连接池,而且我还是不太清楚Connection的close应该干嘛,简单的实现了DataSource,并使用动态代理实现Connection的复用,Connection使用几次以后或者使用一段时间以后再真正的关闭。

代码如下:
package com.jiehoo.core;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.sql.Connection;
import java.sql.SQLException;

public class ReusedConnection implements InvocationHandler {
    private Connection connection;

    private Connection proxyConnection;

    private boolean using;

    private int usedCount;

    private long createTime;

    private int connectionTimeout;

    private int maxUsedCount;

    public ReusedConnection(Connection connection, int connectionTimeout, int maxUsedCount) {
        this.connection = connection;
        this.connectionTimeout = connectionTimeout;
        createTime = System.currentTimeMillis();
        this.maxUsedCount = usedCount;
        proxyConnection = (Connection) Proxy.newProxyInstance(Connection.class.getClassLoader(),
                new Class[] { Connection.class }, this);
    }

    private boolean needClose() {
        return usedCount > maxUsedCount || createTime – System.currentTimeMillis() > connectionTimeout * 1000;
    }

    public boolean isUsing() throws SQLException {
        if (!using && needClose()) {
            using = true;
            close();
        }
        return using;
    }

    public Connection getConnection() {
        return proxyConnection;
    }

    public void setUsing(boolean using) {
        this.using = using;
    }

    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        String methodName = method.getName();
        if (methodName.equals("close")) {
            return close();
        } else {
            return method.invoke(connection, args);
        }
    }

    private Object close() throws SQLException {
        using = false;
        if (!needClose()) {
            connection.commit();
            notifyAll();
        } else {
            connection.close();
        }
        return null;
    }

}

package com.jiehoo.core;

import java.io.PrintWriter;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.List;

import javax.sql.DataSource;

public class SimpleDataSource implements DataSource {
    protected PrintWriter logWriter = new PrintWriter(System.out);

    private String driver;

    private String url;

    private String user;

    private String password;

    private int minConnection;

    private int maxConnection;

    private int connectionTimeout;

    private int getConnectionTimeout;

    private List connections = new ArrayList();

    private int loginTimeout;

    private int connectionUseCount;

    public SimpleDataSource(String driver, String url, String user, String password, int minConnection,
            int maxConnection, int connectionTimeout, int getConnectionTimeout, int loginTimeout, int connectionUseCount) {
        this.driver = driver;
        this.url = url;
        this.user = user;
        this.password = password;
        this.minConnection = minConnection;
        this.maxConnection = maxConnection;
        this.connectionTimeout = connectionTimeout;
        this.getConnectionTimeout = getConnectionTimeout;
        this.loginTimeout = loginTimeout;
        this.connectionUseCount = connectionUseCount;
        init();
    }

    private void init() {
        try {
            Class.forName(driver);
            DriverManager.setLoginTimeout(loginTimeout);
            for (int i = 0; i < minConnection; i++) {
                createConnection();
            }
        } catch (SQLException e) {
            e.printStackTrace(logWriter);
        } catch (ClassNotFoundException e) {
            e.printStackTrace(logWriter);
        }
    }

    public Connection getConnection() throws SQLException {
        Connection connection = getFreeConnection(false);
        if (connection == null) {
            synchronized (connections) {
                if (connections.size() < maxConnection) {
                    connection = createConnection();
                } else {
                    connection = getFreeConnection(true);
                }
            }
        }
        return connection;
    }

    public Connection getConnection(String username, String password) throws SQLException {
        logWriter.write("Do not support this method.");
        return null;
    }

    public PrintWriter getLogWriter() throws SQLException {
        return logWriter;
    }

    public int getLoginTimeout() throws SQLException {
        return loginTimeout;
    }

    public void setLogWriter(PrintWriter out) throws SQLException {
        logWriter = out;
    }

    public void setLoginTimeout(int seconds) throws SQLException {
        this.loginTimeout = seconds;
    }

    private Connection createConnection() throws SQLException {
        Connection connection = DriverManager.getConnection(url, user, password);
        ReusedConnection reusedConnection = new ReusedConnection(connection, connectionTimeout, connectionUseCount);
        connections.add(reusedConnection);
        reusedConnection.setUsing(true);
        return reusedConnection.getConnection();
    }

    public void close() {
        try {
            for (int i = 0; i < connections.size(); i++) {
                ReusedConnection reusedConnection = (ReusedConnection) connections.get(i);
                reusedConnection.getConnection().close();
            }
        } catch (SQLException e) {
            e.printStackTrace(logWriter);
        }
    }

    protected synchronized Connection getFreeConnection(boolean waiting) throws SQLException {
        Connection connection = null;
        for (int i = 0; i < connections.size(); i++) {
            ReusedConnection reusedConnection = (ReusedConnection) connections.get(i);
            if (!reusedConnection.isUsing()) {
                connection = reusedConnection.getConnection();
                if (connection.isClosed()) {
                    connections.remove(i);
                    i–;
                } else {
                    reusedConnection.setUsing(true);
                    break;
                }
            }
        }
        if (connection == null && waiting) {
            try {
                wait(getConnectionTimeout * 1000);
            } catch (InterruptedException e) {
            }
            connection = getFreeConnection(false);
            if (connection == null)
                throw new SQLException("No more available connection.");
        }
        return connection;
    }

}

(Visited 322 times, 1 visits today)

2 Comments

  1. 如果能把你的轮子的总体设计思路最好是那么几张图表示一下的话,我想可以帮助更多的后来者 :em19:

  2. 呵呵,其实我现在还没有总体的思路或者设计,只是有一个简单的目标:快速添加应用功能
    另外就是尽量自己写代码,尽可能少使用第三方的类库或者工具

发表评论

邮箱地址不会被公开。 必填项已用*标注

© 2024 解惑

本主题由Anders Noren提供向上 ↑