一个简单实现的数据库连接池

连接池工作原理:

第一、连接池的建立:一般在系统初始化时,连接池会根据系统配 置建立,并在池中创建了几个连接对象,以便使用时能从连接池中获取。连接池中的连接不能随意创建和关闭,这样避免了连接随意建立和关闭造成的系统开销。 Java中提供了很多容器类可以方便的构建连接池,例如Vector、Stack等。

第二、连接池的管理。连接池管理策略是连接池机制的核心,连接池内连接的分配和释放对系统的性能有很大的影响。其管理策略是: 当客户请求数据库连接时,首先查看连接池中是否有空闲连接,如果存在空闲连接,则将连接分配给客户使用;如果没有空闲连接,则查看当前所开的连接数是否已 经达到最大连接数,如果没达到就重新创建一个连接给请求的客户;如果达到就按设定的最大等待时间进行等待,如果超出最大等待时间,则抛出异常给客户。当客户释放数据库连接时,先判断该连接的引用次数是否超过了规定值,如果超过就从连接池中删除该连接,否则保留为其他客户服务。 该策略保证了数据库连接的有效复用,避免频繁的建立、释放连接所带来的系统资源开销。

第三、连接池的关闭。当应用程序退出时,关闭连接池中所有的连接,释放连接池相关的资源,该过程正好与创建相反。

自实现连接池源码解析:

(1)数据库连接池初始化

public void init(Properties prop) throws BeenInitializedException,
            ClassNotFoundException, SQLException {
        if (init)
            throw new BeenInitializedException(
                    "Database connection pool has been initialized!");
        if (prop == null)
            throw new NullPointerException("prop is null!");
        this.url = prop.getProperty(P_URL);
        this.driver = prop.getProperty(P_DRIVER);
        this.username = prop.getProperty(P_USERNAME);
        this.password = prop.getProperty(P_PASSWORD);
        if (prop.getProperty(P_INIT_CONNECTIONS) != null)
            initialConnections = Integer.parseInt(prop
                    .getProperty(P_INIT_CONNECTIONS));
        if (prop.getProperty(P_INCREMENT_CONNECTIONS) != null)
            incrementalConnections = Integer.parseInt(prop
                    .getProperty(P_INCREMENT_CONNECTIONS));
        if (prop.getProperty(P_MAX_CONNECTIONS) != null)
            maxConnections = Integer.parseInt(prop
                    .getProperty(P_MAX_CONNECTIONS));

        logger.info("Database connection pool parameters:");
        logger.info("url:" + url);
        logger.info("driver:" + driver);
        logger.info("username:" + username);
        logger.info("password:" + password);
        logger.info("initialConnections:" + initialConnections);
        logger.info("incrementalConnections:" + incrementalConnections);
        logger.info("maxConnections:" + maxConnections);

        try {
            logger.info("Load sql driver:" + driver);
            Class.forName(driver);
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
            throw e;
        }

        logger.info("Create initialed connections:" + initialConnections);
        createConnections(initialConnections);
        init = true;
    }

创建初始化的连接数。

/**
     * 创建新连接
     * 
     * @param num
     * @throws SQLException
     */
    private int createConnections(int num) throws SQLException {
        int count = 0;
        for (int i = 0; i < num; i++) {
            if (connections.size() < maxConnections)
                try {
                    Connection conn = DriverManager.getConnection(url,
                            username, password);
                    connections.add(new DBConnection(conn));
                    count++;
                } catch (SQLException e) {
                    e.printStackTrace();
                    throw e;
                }
        }
        return count;
    }

(2)从连接池中获取可用连接

public synchronized Connection getConnection(long time_out_seconds) throws TimeoutException
            {
        logger.info("\n\nCall to get a connection from pool!"+time_out_seconds);
        Connection conn = getIdledConnection();
        if (conn == null) {
            // 扩展连接
            try {
                logger.info("Non ideld connections, create more connections..");
                int count = createConnections(incrementalConnections);
                logger.info("Successfully create connections:" + count);
                if (count > 0)
                    this.notifyAll();
            } catch (SQLException e) {
                e.printStackTrace();
            }
//            int count = 0;
            long last = System.currentTimeMillis();
            long delta = 0;
            while ((conn = getIdledConnection()) == null) {
                try {
                    delta = (time_out_seconds*1000)-(System.currentTimeMillis()-last);
//                    logger.info("Wait...:"+delta/1000+"s!");
                    if(delta <= 0){
                        this.notifyAll();
                        throw new TimeoutException();
                    }
                    this.wait(delta);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
            logger.info("Last get connection:" + conn);
            return conn;
        } else {
            logger.info("First get idled connection:" + conn);
            return conn;
        }
    }

    首先尝试从队列中获取可用的连接。

    如果没有可用连接,则尝试创建更多连接,当然创建连接数不能超过最大连接数。

    如果创建新的连接后还是无可用连接,则等待一段时间, 超时未获取到的话 则抛出超时异常!

   (3)连接释放,返回到池中

public synchronized void release(Connection conn) {
        if (conn == null)
            return;
        for (int i = 0; i < connections.size(); ) {
            DBConnection dbCon = connections.get(i);
            if (dbCon.getConnection() == conn) {
                boolean is = false;
                try {
                    is = conn.isClosed();
                } catch (SQLException e) {
                    try {
                        conn.close();
                    } catch (SQLException e1) {
                        e1.printStackTrace();
                    }
                    is = true;
                }
                if (!is) {
                    dbCon.setState(0);
                    logger.info("A connection is released!");
                    i++;
                }else{
                    connections.remove(i);
                    logger.info("Remove a closed connection!");
                }
            }else{
                i++;
            }
        }
    }

   释放连接的时候,注意同时检测连接是否可用,如果连接不可用可,将其从池中移除。


(4)对Connection的进一步封装

class DBConnection {
        Connection connection;
        long lastTime;
        int state; // 1-working 0-idel

        public DBConnection(Connection conn) {
            connection = conn;
            lastTime = System.currentTimeMillis();
            state = 0;
        }

  其中state主要是用于标示当前connection是否正在使用中,1表示当前连接正在被使用 0-表示当前连接空闲。

(5)从池中获取空闲连接

private Connection getIdledConnection() {
        for (int i = 0; i < connections.size(); i++) {
            DBConnection conn = connections.get(i);
            if (conn.state == 0) {
                conn.setState(1);
                return conn.getConnection();
            }
        }
        return null;
    }

(6)关闭连接池

/**
     * 关闭连接池
     */
    public synchronized void shutDown() {
        for (int i = 0; i < connections.size();) {
            DBConnection dbConn = connections.remove(i);
            try {
                dbConn.getConnection().close();
                logger.info("Close connection:" + dbConn.getConnection());
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }
    }


转载于:https://my.oschina.net/yjwxh/blog/369644

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值