【转】Java的JDBC数据库连接池实现方法
? ? 虽然J2EE程序员一般都有现成的应用服务器所带的JDBC数据库连接池,不过对于开发一般的Java Application、 Applet或者JSP、velocity时,我们可用的JDBC数据库连接池并不多,并且一般性能都不好。
Java程序员都很羡慕Windows ADO ,只需要new Connection 就可以直接从数据库连接池中返回Connection。并且 ADO Connection 是线程安全的,多个线程可以共用一个Connection,所以ASP程序一般都把getConnection 放在 Global.asa 文件中,在 IIS 启动时建立数据库连接。ADO 的Connection 和Result 都有很好的缓冲,并且很容易使用。
其实我们可以自己写一个JDBC数据库连接池。
写JDBC connection pool 的注意事项有:
1. 有一个简单的函数从连接池中得到一个 Connection。
2. close 函数必须将connection 放回 数据库连接池。
3. 当数据库连接池中没有空闲的connection,数据库连接池必须能够自动增加connection 个数。
4. 当数据库连接池中的connection 个数在某一个特别的时间变得很大,但是以后很长时间只用其中一小部分,应该可以自动将多余的connection 关闭掉。
5. 如果可能,应该提供debug 信息报告没有关闭的new Connection 。
如果要new Connection 就可以直接从数据库连接池中返回Connection, 可以这样写( Mediator pattern ) (以下代码中使用了中文全角空格):
- public?class?EasyConnection?implements?java.sql.Connection{ ?
- private?Connection?m_delegate?=?null; ?
- public?EasyConnection(){ ?
- m_delegate?=?getConnectionFromPool(); ?
- } ?
- public?void?close(){ ?
- putConnectionBackToPool(m_delegate); ?
- } ?
- public?PreparedStatement?prepareStatement(String?sql)?throws?SQLException{ ?
- m_delegate.prepareStatement(sql); ?
- } ?
- //......?other?method ?
- }?
看来并不难。不过不建议这种写法,因为应该尽量避免使用Java Interface, 关于Java Interface 的缺点我另外再写文章讨论。大家关注的是Connection Pool 的实现方法。下面给出一种实现方法。
- import?java.sql.*; ?
- import?java.lang.reflect.*; ?
- import?java.util.*; ?
- import?java.io.*; ?
- ?
- public?class?SimpleConnetionPool?{ ?
- private?static?LinkedList?m_notUsedConnection?=?new?LinkedList(); ?
- private?static?HashSet?m_usedUsedConnection?=?new?HashSet(); ?
- private?static?String?m_url?=?""; ?
- private?static?String?m_user?=?""; ?
- private?static?String?m_password?=?""; ?
- static?final?boolean?DEBUG?=?true; ?
- static?private?long?m_lastClearClosedConnection?=?System.currentTimeMillis(); ?
- public?static?long?CHECK_CLOSED_CONNECTION_TIME?=?4?*?60?*?60?*?1000;?//4?hours ?
- ?
- static?{ ?
- initDriver(); ?
- } ?
- ?
- private?SimpleConnetionPool()?{ ?
- } ?
- ?
- private?static?void?initDriver()?{ ?
- Driver?driver?=?null; ?
- //load?mysql?driver ?
- try?{ ?
- driver?=?(Driver)?Class.forName("com.mysql.jdbc.Driver").newInstance(); ?
- installDriver(driver); ?
- }?catch?(Exception?e)?{ ?
- } ?
- ?
- //load?postgresql?driver ?
- try?{ ?
- driver?=?(Driver)?Class.forName("org.postgresql.Driver").newInstance(); ?
- installDriver(driver); ?
- }?catch?(Exception?e)?{ ?
- } ?
- } ?
- ?
- public?static?void?installDriver(Driver?driver)?{ ?
- try?{ ?
- DriverManager.registerDriver(driver); ?
- }?catch?(Exception?e)?{ ?
- e.printStackTrace(); ?
- } ?
- } ?
- ?
- ?
- public?static?synchronized?Connection?getConnection()?{ ?
- clearClosedConnection(); ?
- while?(m_notUsedConnection.size()?>?0)?{ ?
- try?{ ?
- ConnectionWrapper?wrapper?=?(ConnectionWrapper)?m_notUsedConnection.removeFirst(); ?
- if?(wrapper.connection.isClosed())?{ ?
- continue; ?
- } ?
- m_usedUsedConnection.add(wrapper); ?
- if?(DEBUG)?{ ?
- wrapper.debugInfo?=?new?Throwable("Connection?initial?statement"); ?
- } ?
- return?wrapper.connection; ?
- }?catch?(Exception?e)?{ ?
- } ?
- } ?
- int?newCount?=?getIncreasingConnectionCount(); ?
- LinkedList?list?=?new?LinkedList(); ?
- ConnectionWrapper?wrapper?=?null; ?
- for?(int?i?=?0;?i?<?newCount;?i++)?{ ?
- wrapper?=?getNewConnection(); ?
- if?(wrapper?!=?null)?{ ?
- list.add(wrapper); ?
- } ?
- } ?
- if?(list.size()?==?0)?{ ?
- return?null; ?
- } ?
- wrapper?=?(ConnectionWrapper)?list.removeFirst(); ?
- m_usedUsedConnection.add(wrapper); ?
- ?
- m_notUsedConnection.addAll(list); ?
- list.clear(); ?
- ?
- return?wrapper.connection; ?
- } ?
- ?
- private?static?ConnectionWrapper?getNewConnection()?{ ?
- try?{ ?
- Connection?con?=?DriverManager.getConnection(m_url,?m_user,?m_password); ?
- ConnectionWrapper?wrapper?=?new?ConnectionWrapper(con); ?
- return?wrapper; ?
- }?catch?(Exception?e)?{ ?
- e.printStackTrace(); ?
- } ?
- return?null; ?
- } ?
- ?
- static?synchronized?void?pushConnectionBackToPool(ConnectionWrapper?con)?{ ?
- boolean?exist?=?m_usedUsedConnection.remove(con); ?
- if?(exist)?{ ?
- m_notUsedConnection.addLast(con); ?
- } ?
- } ?
- ?
- public?static?int?close()?{ ?
- int?count?=?0; ?
- ?
- Iterator?iterator?=?m_notUsedConnection.iterator(); ?
- while?(iterator.hasNext())?{ ?
- try?{ ?
- (?(ConnectionWrapper)?iterator.next()).close(); ?
- count++; ?
- }?catch?(Exception?e)?{ ?
- } ?
- } ?
- m_notUsedConnection.clear(); ?
- ?
- iterator?=?m_usedUsedConnection.iterator(); ?
- while?(iterator.hasNext())?{ ?
- try?{ ?
- ConnectionWrapper?wrapper?=?(ConnectionWrapper)?iterator.next(); ?
- wrapper.close(); ?
- if?(DEBUG)?{ ?
- wrapper.debugInfo.printStackTrace(); ?
- } ?
- count++; ?
- }?catch?(Exception?e)?{ ?
- } ?
- } ?
- m_usedUsedConnection.clear(); ?
- ?
- return?count; ?
- } ?
- ?
- private?static?void?clearClosedConnection()?{ ?
- long?time?=?System.currentTimeMillis(); ?
- //sometimes?user?change?system?time,just?return ?
- if?(time?<?m_lastClearClosedConnection)?{ ?
- time?=?m_lastClearClosedConnection; ?
- return; ?
- } ?
- //no?need?check?very?often ?
- if?(time?-?m_lastClearClosedConnection?<?CHECK_CLOSED_CONNECTION_TIME)?{ ?
- return; ?
- } ?
- m_lastClearClosedConnection?=?time; ?
- ?
- //begin?check ?
- Iterator?iterator?=?m_notUsedConnection.iterator(); ?
- while?(iterator.hasNext())?{ ?
- ConnectionWrapper?wrapper?=?(ConnectionWrapper)?iterator.next(); ?
- try?{ ?
- if?(wrapper.connection.isClosed())?{ ?
- iterator.remove(); ?
- } ?
- }?catch?(Exception?e)?{ ?
- iterator.remove(); ?
- if?(DEBUG)?{ ?
- System.out.println("connection?is?closed,?this?connection?initial?StackTrace"); ?
- wrapper.debugInfo.printStackTrace(); ?
- } ?
- } ?
- } ?
- ?
- //make?connection?pool?size?smaller?if?too?big ?
- int?decrease?=?getDecreasingConnectionCount(); ?
- if?(m_notUsedConnection.size()?<?decrease)?{ ?
- return; ?
- } ?
- ?
- while?(decrease--?>?0)?{ ?
- ConnectionWrapper?wrapper?=?(ConnectionWrapper)?m_notUsedConnection.removeFirst(); ?
- try?{ ?
- wrapper.connection.close(); ?
- }?catch?(Exception?e)?{ ?
- } ?
- } ?
- } ?
- ?
- /** ?
- ?*?get?increasing?connection?count,?not?just?add?1?connection ?
- ?*?@return?count ?
- ?*/?
- public?static?int?getIncreasingConnectionCount()?{ ?
- int?count?=?1; ?
- int?current?=?getConnectionCount(); ?
- count?=?current?/?4; ?
- if?(count?<?1)?{ ?
- count?=?1; ?
- } ?
- return?count; ?
- } ?
- ?
- /** ?
- ?*?get?decreasing?connection?count,?not?just?remove?1?connection ?
- ?*?@return?count ?
- ?*/?
- public?static?int?getDecreasingConnectionCount()?{ ?
- int?count?=?0; ?
- int?current?=?getConnectionCount(); ?
- if?(current?<?10)?{ ?
- return?0; ?
- } ?
- return?current?/?3; ?
- } ?
- ?
- public?synchronized?static?void?printDebugMsg()?{ ?
- printDebugMsg(System.out); ?
- } ?
- ?
- public?synchronized?static?void?printDebugMsg(PrintStream?out)?{ ?
- if?(DEBUG?==?false)?{ ?
- return; ?
- } ?
- StringBuffer?msg?=?new?StringBuffer(); ?
- msg.append("debug?message?in?"?+?SimpleConnetionPool.class.getName()); ?
- msg.append("\r\n"); ?
- msg.append("total?count?is?connection?pool:?"?+?getConnectionCount()); ?
- msg.append("\r\n"); ?
- msg.append("not?used?connection?count:?"?+?getNotUsedConnectionCount()); ?
- msg.append("\r\n"); ?
- msg.append("used?connection,?count:?"?+?getUsedConnectionCount()); ?
- out.println(msg); ?
- Iterator?iterator?=?m_usedUsedConnection.iterator(); ?
- while?(iterator.hasNext())?{ ?
- ConnectionWrapper?wrapper?=?(ConnectionWrapper)?iterator.next(); ?
- wrapper.debugInfo.printStackTrace(out); ?
- } ?
- out.println(); ?
- } ?
- ?
- public?static?synchronized?int?getNotUsedConnectionCount()?{ ?
- return?m_notUsedConnection.size(); ?
- } ?
- ?
- public?static?synchronized?int?getUsedConnectionCount()?{ ?
- return?m_usedUsedConnection.size(); ?
- } ?
- ?
- public?static?synchronized?int?getConnectionCount()?{ ?
- return?m_notUsedConnection.size()?+?m_usedUsedConnection.size(); ?
- } ?
- ?
- public?static?String?getUrl()?{ ?
- return?m_url; ?
- } ?
- ?
- public?static?void?setUrl(String?url)?{ ?
- if?(url?==?null)?{ ?
- return; ?
- } ?
- m_url?=?url.trim(); ?
- } ?
- ?
- public?static?String?getUser()?{ ?
- return?m_user; ?
- } ?
- ?
- public?static?void?setUser(String?user)?{ ?
- if?(user?==?null)?{ ?
- return; ?
- } ?
- m_user?=?user.trim(); ?
- } ?
- ?
- public?static?String?getPassword()?{ ?
- return?m_password; ?
- } ?
- ?
- public?static?void?setPassword(String?password)?{ ?
- if?(password?==?null)?{ ?
- return; ?
- } ?
- m_password?=?password.trim(); ?
- } ?
- ?
- } ?
- ?
- class?ConnectionWrapper?implements?InvocationHandler?{ ?
- private?final?static?String?CLOSE_METHOD_NAME?=?"close"; ?
- public?Connection?connection?=?null; ?
- private?Connection?m_originConnection?=?null; ?
- public?long?lastAccessTime?=?System.currentTimeMillis(); ?
- Throwable?debugInfo?=?new?Throwable("Connection?initial?statement"); ?
- ?
- ConnectionWrapper(Connection?con)?{ ?
- this.connection?=?(Connection)?Proxy.newProxyInstance( ?
- con.getClass().getClassLoader(), ?
- con.getClass().getInterfaces(),?this); ?
- m_originConnection?=?con; ?
- } ?
- ?
- void?close()?throws?SQLException?{ ?
- m_originConnection.close(); ?
- } ?
- ?
- public?Object?invoke(Object?proxy,?Method?m,?Object[]?args)?throws?Throwable?{ ?
- Object?obj?=?null; ?
- if?(CLOSE_METHOD_NAME.equals(m.getName()))?{ ?
- SimpleConnetionPool.pushConnectionBackToPool(this); ?
- } ?
- else?{ ?
- obj?=?m.invoke(m_originConnection,?args); ?
- } ?
- lastAccessTime?=?System.currentTimeMillis(); ?
- return?obj; ?
- } ?
- }?
使用方法
- public?class?TestConnectionPool{ ?
- public?static?void?main(String[]?args)?{ ?
- SimpleConnetionPool.setUrl(DBTools.getDatabaseUrl()); ?
- SimpleConnetionPool.setUser(DBTools.getDatabaseUserName()); ?
- SimpleConnetionPool.setPassword(DBTools.getDatabasePassword()); ?
- ?
- Connection?con?=?SimpleConnetionPool.getConnection(); ?
- Connection?con1?=?SimpleConnetionPool.getConnection(); ?
- Connection?con2?=?SimpleConnetionPool.getConnection(); ?
- ?
- //do?something?with?con?... ?
- ?
- try?{ ?
- con.close(); ?
- }?catch?(Exception?e)?{} ?
- ?
- try?{ ?
- con1.close(); ?
- }?catch?(Exception?e)?{} ?
- ?
- try?{ ?
- con2.close(); ?
- }?catch?(Exception?e)?{} ?
- ?
- con?=?SimpleConnetionPool.getConnection(); ?
- con1?=?SimpleConnetionPool.getConnection(); ?
- try?{ ?
- con1.close(); ?
- }?catch?(Exception?e)?{} ?
- ?
- con2?=?SimpleConnetionPool.getConnection(); ?
- SimpleConnetionPool.printDebugMsg(); ?
- ?
- } ?
- }?
运行测试程序后打印JDBC数据库连接池中Connection状态,以及正在使用的没有关闭Connection信息。