本文共 7907 字,大约阅读时间需要 26 分钟。
最近跟随Tomcat7.0开发了一个JDBC 连接池。
Svn: http://svn.apache.org/repos/asf/tomcat/trunk/modules/jdbc-pool
上大篇幅的介绍,包括基本的使用指南。本篇从源码的角度,分析该连接池的实现思路。
应用使用JDBC连接也,主要关注以下三个方面:
1. 获取连接
2. 归还连接
3.空闲连接关闭。
一. 获取连接
ConnectionPool提供三个接口用于获取连接:
- public Future<Connection> getConnectionAsync() throws SQLException {
-
- try {
-
- PooledConnection pc = borrowConnection(0, null, null);
-
- if (pc!=null) {
-
- return new ConnectionFuture(pc);
-
- }
-
- }catch (SQLException x) {
-
- if (x.getMessage().indexOf("NoWait")<0) {
-
- throw x;
-
- }
-
- }
-
- /we can only retrieve a future if the underlying queue supports it.
-
- if (idle instanceof FairBlockingQueue<?>) {
-
- Future<PooledConnection> pcf = ((FairBlockingQueue<PooledConnection>)idle).pollAsync();
-
- return new ConnectionFuture(pcf);
-
- } else if (idle instanceof MultiLockFairBlockingQueue<?>) {
-
- Future<PooledConnection> pcf = ((MultiLockFairBlockingQueue<PooledConnection>)idle).pollAsync();
-
- return new ConnectionFuture(pcf);
-
- } else {
-
- throw new SQLException("Connection pool is misconfigured, doesn't support async retrieval. Set the 'fair' property to 'true'");
-
- }
-
-
-
- public Connection getConnection() throws SQLException {
-
-
-
- PooledConnection con = borrowConnection(-1,null,null);
-
- return setupConnection(con);
-
- }
-
- public Connection getConnection(String username, String password) throws SQLException {
-
-
-
- PooledConnection con = borrowConnection(-1, username, password);
-
- return setupConnection(con);
-
- }
第一个方法:getConnectionAsync用于获取一个连接的Feature.它用于支持以异步的方式获取连接。后两个方法不同之处就是传递了所需连接的用户名与密码。我们这里得点分析第三个方法.
PooledConnection con = borrowConnection(-1, username, password);
borrowConnection方法从空闲队列中获取一个连接,或新建一个连接。看一下源码:
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- private PooledConnection borrowConnection(int wait, String username, String password) throws SQLException {
-
-
-
- if (isClosed()) {
-
- throw new SQLException("Connection pool closed.");
-
- }
-
-
-
-
-
- long now = System.currentTimeMillis();
-
-
-
-
-
-
-
-
-
- PooledConnection con = idle.poll();
-
- while (true) {
-
- if (con!=null) {
-
-
-
-
-
- PooledConnection result = borrowConnection(now, con, username, password);
-
-
-
-
-
-
-
- if (result!=null) return result;
-
- }
-
-
-
-
-
-
-
-
-
-
-
-
- if (size.get() < getPoolProperties().getMaxActive()) {
-
-
-
- if (size.addAndGet(1) > getPoolProperties().getMaxActive()) {
-
-
-
- size.decrementAndGet();
-
- } else {
-
-
-
-
-
- return createConnection(now, con, username, password);
-
- }
-
- }
-
-
-
-
-
- long maxWait = wait;
-
-
-
-
-
- if (wait==-1) {
-
- maxWait = (getPoolProperties().getMaxWait()<=0)?Long.MAX_VALUE:getPoolProperties().getMaxWait();
-
- }
-
-
-
- long timetowait = Math.max(0, maxWait - (System.currentTimeMillis() - now));
-
- waitcount.incrementAndGet();
-
- try {
-
-
-
- con = idle.poll(timetowait, TimeUnit.MILLISECONDS);
-
- } catch (InterruptedException ex) {
-
- if (getPoolProperties().getPropagateInterruptState()) {
-
- Thread.currentThread().interrupt();
-
- } else {
-
- Thread.interrupted();
-
- }
-
- SQLException sx = new SQLException("Pool wait interrupted.");
-
- sx.initCause(ex);
-
- throw sx;
-
- } finally {
-
- waitcount.decrementAndGet();
-
- }
-
-
-
- if (maxWait==0 && con == null) {
-
- throw new PoolExhaustedException("[" + Thread.currentThread().getName()+"] " +
-
- "NoWait: Pool empty. Unable to fetch a connection, none available["+busy.size()+" in use].");
-
- }
-
-
-
- if (con == null) {
-
- …
-
- if ((System.currentTimeMillis() - now) >= maxWait) {
-
- 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 {
-
-
-
-
-
- continue;
-
- }
-
- }
-
- }
-
- }
waitTime表示连接请求者容忍等待的最大时间,超时没有获取到连接则抛出PoolExhaustedException异常。OK。
下面我们看中间遇到的borrowConnection的重载方法:
protected PooledConnection borrowConnection(long now, PooledConnection con, String username, String password)
和
protected PooledConnection createConnection(long now, PooledConnection notUsed, String username, String password)
首先看第一个:
-
-
-
-
-
-
-
-
-
-
-
-
-
- protected PooledConnection borrowConnection(long now, PooledConnection con, String username, String password) throws SQLException {
-
-
-
-
-
- boolean setToNull = false;
-
- try {
-
-
-
- con.lock();
-
-
-
- boolean usercheck = con.checkUser(username, password);
-
- if (con.isReleased()) {
-
- return null;
-
- }
-
-
-
- if (!con.isDiscarded() && !con.isInitialized()) {
-
-
-
- try {
-
- con.connect();
-
- } catch (Exception x) {
-
- release(con);
-
- setToNull = true;
-
- if (x instanceof SQLException) {
-
- throw (SQLException)x;
-
- } else {
-
- SQLException ex = new SQLException(x.getMessage());
-
- ex.initCause(x);
-
- throw ex;
-
- }
-
- }
-
- }
-
-
-
- if (usercheck) {
-
- if ((!con.isDiscarded()) && con.validate(PooledConnection.VALIDATE_BORROW)) {
-
-
-
- con.setTimestamp(now);
-
-
-
-
-
- if (getPoolProperties().isLogAbandoned()) {
-
-
-
- con.setStackTrace(getThreadDump());
-
- }
-
-
-
- if (!busy.offer(con)) {
-
- log.debug("Connection doesn't fit into busy array, connection will not be traceable.");
-
- }
-
- return con;
-
- }
-
- }
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- try {
-
- con.reconnect();
-
- if (con.validate(PooledConnection.VALIDATE_INIT)) {
-
-
-
- con.setTimestamp(now);
-
- if (getPoolProperties().isLogAbandoned()) {
-
-
-
- con.setStackTrace(getThreadDump());
-
- }
-
- if (!busy.offer(con)) {
-
- log.debug("Connection doesn't fit into busy array, connection will not be traceable.");
-
- }
-
- return con;
-
- } else {
-
-
-
- release(con);
-
- setToNull = true;
-
- throw new SQLException("Failed to validate a newly established connection.");
-
- }
-
- } catch (Exception x) {
-
- release(con);
-
- setToNull = true;
-
- if (x instanceof SQLException) {
-
- throw (SQLException)x;
-
- } else {
-
- SQLException ex = new SQLException(x.getMessage());
-
- ex.initCause(x);
-
- throw ex;
-
- }
-
- }
-
- } finally {
-
- con.unlock();
-
- if (setToNull) {
-
- con = null;
-
- }
-
- }
-
- }
(待续)
转载地址:http://omfvl.baihongyu.com/