读书人

相干数据库连接池的一些思考

发布时间: 2012-11-14 10:12:18 作者: rapoo

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

以前写一些作业性质的网站,在对数据库操作时,都会写一个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("读取属性文件出错. ");                }    }}

?连接池的大小应该根据系统的空闲状况灵活的改变连接的数量。比如请求高峰到来时,池中的连接数可能已经到了最大值,系统总是维持这么多的连接是很消耗资源的,因此应该有一个机制不断地减小连接。当然,这需要用到线程。

ConnectionManager.java

import java.sql.Connection;import java.util.Vector;public class ConnectionManager extends Thread{/*连接池最小的链接数量*/public static int MIN_SIZE = 3;    private Vector<Connection> pool;public ConnectionManager(Vector<Connection> pool){this.pool = pool;}public void run() {while(pool.size()>MIN_SIZE)  {pool.setSize(pool.size()-1);try {Thread.sleep(1000);} catch (InterruptedException e) {e.printStackTrace();}}}}

?

下面是连接数据库的属性文件

driverClassName=com.microsoft.jdbc.sqlserver.SQLServerDriverusername=sapassword=123456url=jdbc:microsoft:sqlserver://localhost:1433/estorepoolSizeMax=10poolSizeMin=3

?

最后,我同时用了3个线程来不断地获取连接,测试结果表明,使用连接池之后,效率提高了100%。而且,如果线程越多,连接池的优势将更加明显。

1 楼 wh8766 2009-03-07 思想上是理解了
有点地方看的晕乎,博主能给解释下么
getConnection() 的流程,谢谢
最近也在看数据库连接池的东西,没自己写直接用的Proxool组件…… 2 楼 nmj1987 2009-03-08 最近看《java服务器高级编程》,里面提到数据库连接池,我这个属于传统的连接池,现在已经很少用了。getConnection() 的流程是这样的,初始化的时候不是建立了3个连接吗,一个用户来申请,占用一个,只剩两个了,那么pool.size()就等于2了。又分别来两个用户连接,size等于0了。如果在这三个用户释放连接前,又有新的连接请求,只要poolSize小于poolSizeMax的一半,那么就把poolSize翻倍,变成6。当6个连接有被用完了,但poolSize大于于poolSizeMax的一半,那就只好把poolSize扩大到poolSizeMax了。 3 楼 wh8766 2009-03-08 恩 了解了~
3Q3Q

读书人网 >其他数据库

热点推荐