日期:2014-05-16  浏览次数:20587 次

有关数据库连接池的一些思考

以前写一些作业性质的网站,在对数据库操作时,都会写一个DBConnection类,用来获取数据库的连接,操作完数据之后,马上释放该连接。这是最简单的方法,但性能上是有很大问题的。比如我曾经用单线程循环1000次数据操作,就会出现异常。这时,使用连接池效果会好不少。下面的代码是在别人基础上稍加修改而来的。

以下是一个数据库连接池,启动时先从属性文件中读出一些参数,并启动最小连接数。有外来请求,就从连接池中移走一个对象。当前连接池大小为0时,参考最大连接数,新建若干个链接。当连接数超出最大限制时,则不再新建连接,这时如果有新的连接请求,而连接池目前又没有空闲的连接的话,那就很抱歉,只能返回空了。(返回空必然会引发异常,这不是我们所希望看到的。谁如果有好的解决方案,望告知)。

ConnectionPool.java

import java.io.FileInputStream;
import java.sql.Connection;
import java.sql.SQLException;
import java.util.Properties;
import java.util.Vector;

public class ConnectionPool {

    private Vector<Connection> pool;

    private String url;

    private String username;

    private String password;

    private String driverClassName;

    /** 
     * 连接池的大小,也就是连接池中有多少个数据库连接。
     */
    private int poolSize;
    
    private int poolSizeMax;

    private static ConnectionPool instance = new ConnectionPool();

    private ConnectionManager connectionManager;
    /** 
     * 私有的构造方法,禁止外部创建本类的对象,要想获得本类的对象,通过<code>getIstance</code>方法。
     * 使用了设计模式中的单子模式。
     */
    private ConnectionPool() {
        init();
    }

    /** 
     * 连接池初始化方法,读取属性文件的内容 建立连接池中的初始连接
     */
    private void init() {
        pool = new Vector<Connection>();
        readConfig();
        addConnection(poolSize);
        connectionManager = new ConnectionManager(pool);
        connectionManager.start();
    }

    /** 
     * 返回连接到连接池中
     */
    public synchronized void release(Connection conn) {
        pool.add(conn);

    }

    /** 
     * 关闭连接池中的所有数据库连接
     */
    public synchronized void closePool() {
        for (int i = 0; i < pool.size(); i++) {
            try {
                ((Connection) pool.get(i)).close();
            } catch (SQLException e) {
                e.printStackTrace();
            }
            pool.remove(i);
        }
    }

    /** 
     * 返回当前连接池的一个对象
     */
    public static ConnectionPool getInstance() {
        return instance;
    }

    /** 
     * 返回连接池中的一个数据库连接
     */
    public synchronized Connection getConnection() { 
    	Connection conn;
        if (pool.size() <= 0) {
              if(poolSize<=(poolSizeMax>>2)) {
        		addConnection(poolSize);
        		poolSize<<=2;	
        	}
        	else if(poolSize<poolSizeMax){
        		addConnection(poolSize);
            	poolSize=poolSizeMax; 	
        	}
        }
        conn = pool.remove(0);//pool.get(0),pool的size并不会减1
    	return conn;
    }

    /** 
     * 在连接池中创建初始设置的的数据库连接
     */
    private void addConnection(int size) {
        Connection conn = null;
        for (int i = 0; i < size; i++) {

            try {
                Class.forName(driverClassName);
                conn = java.sql.DriverManager.getConnection(url, username, password);
                pool.add(conn);
            } catch (ClassNotFoundException e) {
                e.printStackTrace();
            } catch (SQLException e) {
                e.printStackTrace();
            }

        }
    }

    /** 
     * 读取设置连接池的属性文件
     */
    private void readConfig() {
        try {
            String path = System.getProperty("user.dir") + "\\dbpool.properties";
            FileInputStream is = new FileInputStream(path);
            Properties props = new Properties();
            props.load(is);
            this.driverClassName = props.getProperty("driverClassName");
            this.username = props.getProperty("username");
            this.password = props.getProperty("password");
            this.url = props.getProperty("url");
            this.poolSize = Integer.parseInt(props.getProperty("poolSizeMin"));
            this.poolSizeMax = Integer.parseInt(props.getProperty("poolSizeMax"));
        } catch (Exception e) {
            e.printStackTrace();
            System.err.println("读取属性文件出错. ");        
        }
    }
}

?连接池的大小应该根据系统的空闲状况灵活的改变连接的数量。比如请求高峰到来时,池中的连接数可能已经到了最大值,系统总是维持这么多的连接是很消