tomcat jdbc数据库连接池详解之获取连接

2022-03-28 20:07:35 浏览数 (1)

数据库连接是一种宝贵资源,其建立过程需要tcp握手以及登录校验(验证用户名、密码),这也是一个比较昂贵的过程,如果不使用数据库连接池技术,频繁的创建连接、释放连接将会对系统性能有很大影响。那么数据库连接池是怎样高效的返回连接并管理这些创建好的数据库连接的呢?

本文要讲述的内容涉及到org.apache.tomcat.jdbc.pool.ConnectionPool类以及相关的两个属性:

代码语言:javascript复制
    private BlockingQueue<PooledConnection> busy;
     private BlockingQueue<PooledConnection> idle;
代码语言:javascript复制
    public Connection getConnection() throws SQLException {
        //check out a connection
        PooledConnection con = borrowConnection(-1,null,null);
        //设置该连接,设置JdbcInterceptor调用链
        return setupConnection(con);
    }

这就是tomcat jdbc连接池返回数据库连接的地方:

1.先从连接池从“借”一个连接(如果idle队列没有剩余连接则根据实际情况决定是否要创建新的连接)

2.初始化该连接

代码语言:javascript复制
    private PooledConnection borrowConnection(int wait, String username, String password) throws SQLException {

        if (isClosed()) {
            throw new SQLException("Connection pool closed.");
        } //end if

        //get the current time stamp
        long now = System.currentTimeMillis();
        //see if there is one available immediately
        PooledConnection con = idle.poll();

        while (true) {
            if (con!=null) {
                //configure the connection and return it
                //这里返回的连接会被加入到busy队列中,而returnConnection则会将busy中的连接移除并根据实际情况决定是否需要添加到idle队列中
                PooledConnection result = borrowConnection(now, con, username, password);
                borrowedCount.incrementAndGet();
                if (result!=null) return result;
            }

            //if we get here, see if we need to create one
            //this is not 100% accurate since it doesn't use a shared
            //atomic variable - a connection can become idle while we are creating
            //a new connection
            if (size.get() < getPoolProperties().getMaxActive()) {
                //atomic duplicate check
                if (size.addAndGet(1) > getPoolProperties().getMaxActive()) {
                    //if we got here, two threads passed through the first if
                    size.decrementAndGet();
                } else {
                    //create a connection, we're below the limit
                    return createConnection(now, con, username, password);
                }
            } //end if

            //calculate wait time for this iteration
            long maxWait = wait;
            //if the passed in wait time is -1, means we should use the pool property value
            if (wait==-1) {
                maxWait = (getPoolProperties().getMaxWait()<=0)?Long.MAX_VALUE:getPoolProperties().getMaxWait();
            }

            long timetowait = Math.max(0, maxWait - (System.currentTimeMillis() - now));
            waitcount.incrementAndGet();
            try {
                //retrieve an existing connection
                con = idle.poll(timetowait, TimeUnit.MILLISECONDS);
            } catch (InterruptedException ex) {
                if (getPoolProperties().getPropagateInterruptState()) {
                    Thread.currentThread().interrupt();
                }
                SQLException sx = new SQLException("Pool wait interrupted.");
                sx.initCause(ex);
                throw sx;
            } finally {
                waitcount.decrementAndGet();
            }
            if (maxWait==0 && con == null) { //no wait, return one if we have one
                if (jmxPool!=null) {
                    jmxPool.notify(org.apache.tomcat.jdbc.pool.jmx.ConnectionPool.POOL_EMPTY, "Pool empty - no wait.");
                }
                throw new PoolExhaustedException("["   Thread.currentThread().getName() "] "  
                        "NoWait: Pool empty. Unable to fetch a connection, none available[" busy.size() " in use].");
            }
            //we didn't get a connection, lets see if we timed out
            if (con == null) {
                if ((System.currentTimeMillis() - now) >= maxWait) {
                    if (jmxPool!=null) {
                        jmxPool.notify(org.apache.tomcat.jdbc.pool.jmx.ConnectionPool.POOL_EMPTY, "Pool empty - timeout.");
                    }
                    throw new PoolExhaustedException("["   Thread.currentThread().getName() "] "  
                        "Timeout: Pool empty. Unable to fetch a connection in "   (maxWait / 1000)  
                        " seconds, none available[size:" size.get()  "; busy:" busy.size() "; idle:" idle.size() "; lastwait:" timetowait "].");
                } else {
                    //no timeout, lets try again
                    continue;
                }
            }
        } //while
    }

以上就是tomcat jdbc连接池返回连接的大致流程,感兴趣的可以打开ConnectionPool的源码进一步分析

0 人点赞