﻿<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:trackback="http://madskills.com/public/xml/rss/module/trackback/" xmlns:wfw="http://wellformedweb.org/CommentAPI/" xmlns:slash="http://purl.org/rss/1.0/modules/slash/"><channel><title>BlogJava-我的小船停在代码的海洋中...-随笔分类-工作</title><link>http://www2.blogjava.net/machilansing/category/13689.html</link><description>Lansing--Coding 不是梦
</description><language>zh-cn</language><lastBuildDate>Wed, 28 Feb 2007 20:20:10 GMT</lastBuildDate><pubDate>Wed, 28 Feb 2007 20:20:10 GMT</pubDate><ttl>60</ttl><item><title>Java 的JDBC 数据库连接池实现方法</title><link>http://www.blogjava.net/machilansing/archive/2006/08/04/61776.html</link><dc:creator>Lansing</dc:creator><author>Lansing</author><pubDate>Fri, 04 Aug 2006 07:56:00 GMT</pubDate><guid>http://www.blogjava.net/machilansing/archive/2006/08/04/61776.html</guid><wfw:comment>http://www.blogjava.net/machilansing/comments/61776.html</wfw:comment><comments>http://www.blogjava.net/machilansing/archive/2006/08/04/61776.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/machilansing/comments/commentRss/61776.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/machilansing/services/trackbacks/61776.html</trackback:ping><description><![CDATA[Java 的JDBC 数据库连接池实现方法 <br /><br />关键字: Java, JDBC, Connection Pool, Database, 数据库连接池, sourcecode<br /><br />  虽然 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 都有很好的缓冲，并且很容易使用。<br /><br />其实我们可以自己写一个JDBC 数据库连接池。写 JDBC connection pool 的注意事项有：<br /><br />1. 有一个简单的函数从连接池中得到一个 Connection。 <br />2. close 函数必须将 connection 放回 数据库连接池。 <br />3. 当数据库连接池中没有空闲的 connection， 数据库连接池必须能够自动增加 connection 个数。 <br />4. 当数据库连接池中的 connection 个数在某一个特别的时间变得很大，但是以后很长时间只用其中一小部分，应该可以自动将多余的 connection 关闭掉。 <br />5. 如果可能，应该提供debug 信息报告没有关闭的 new Connection 。 <br /><br />如果要 new Connection 就可以直接从数据库连接池中返回 Connection， 可以这样写( Mediator pattern ) (以下代码中使用了中文全角空格)：<br /><br /><pre class="overflow">public class EasyConnection implements java.sql.Connection{<br />　　private Connection m_delegate = null;<br /><br />　　public EasyConnection(){<br />　　　　m_delegate = getConnectionFromPool();<br />　　}<br /><br />　　public void close(){<br />　　　　putConnectionBackToPool(m_delegate);<br />　　}<br /><br />　　public PreparedStatement prepareStatement(String sql) throws SQLException{<br />　　　　m_delegate.prepareStatement(sql);<br />　　}<br /><br />　　//...... other method<br /><br />}</pre><br /><br />看来并不难。不过不建议这种写法，因为应该尽量避免使用 Java Interface, 关于 Java Interface 的缺点我另外再写文章讨论。大家关注的是 Connection Pool 的实现方法。下面给出一种实现方法。 <br /><br /><pre class="overflow">import java.sql.*;<br />import java.lang.reflect.*;<br />import java.util.*;<br />import java.io.*;<br /><br />public class SimpleConnetionPool {<br />　　private static LinkedList m_notUsedConnection = new LinkedList();<br />　　private static HashSet m_usedUsedConnection = new HashSet();<br />　　private static String m_url = "";<br />　　private static String m_user = "";<br />　　private static String m_password = "";<br />　　static final boolean DEBUG = true;<br />　　static private long m_lastClearClosedConnection = System.currentTimeMillis();<br />　　public static long CHECK_CLOSED_CONNECTION_TIME = 4 * 60 * 60 * 1000; //4 hours<br /><br />　　static {<br />　　　　initDriver();<br />　　}<br /><br />　　private SimpleConnetionPool() {<br />　　}<br /><br />　　private static void initDriver() {<br />　　　　Driver driver = null;<br />　　　　//load mysql driver<br />　　　　try {<br />　　　　　　driver = (Driver) Class.forName("com.mysql.jdbc.Driver").newInstance();<br />　　　　　　installDriver(driver);<br />　　　　} catch (Exception e) {<br />　　　　}<br /><br />　　　　//load postgresql driver<br />　　　　try {<br />　　　　　　driver = (Driver) Class.forName("org.postgresql.Driver").newInstance();<br />　　　　　　installDriver(driver);<br />　　　　} catch (Exception e) {<br />　　　　}<br />　　}<br /><br />　　public static void installDriver(Driver driver) {<br />　　　　try {<br />　　　　　　DriverManager.registerDriver(driver);<br />　　　　} catch (Exception e) {<br />　　　　　　e.printStackTrace();<br />　　　　}<br />　　}<br /><br /><br />　　public static synchronized Connection getConnection() {<br />　　　　clearClosedConnection();<br />　　　　while (m_notUsedConnection.size() &gt; 0) {<br />　　　　　　try {<br />　　　　　　　　ConnectionWrapper wrapper = (ConnectionWrapper) m_notUsedConnection.removeFirst();<br />　　　　　　　　if (wrapper.connection.isClosed()) {<br />　　　　　　　　　　continue;<br />　　　　　　　　}<br />　　　　　　　　m_usedUsedConnection.add(wrapper);<br />　　　　　　　　if (DEBUG) {<br />　　　　　　　　　　wrapper.debugInfo = new Throwable("Connection initial statement");<br />　　　　　　　　}<br />　　　　　　　　return wrapper.connection;<br />　　　　　　} catch (Exception e) {<br />　　　　　　}<br />　　　　}<br />　　　　int newCount = getIncreasingConnectionCount();<br />　　　　LinkedList list = new LinkedList();<br />　　　　ConnectionWrapper wrapper = null;<br />　　　　for (int i = 0; i &lt; newCount; i++) {<br />　　　　　　wrapper = getNewConnection();<br />　　　　　　if (wrapper != null) {<br />　　　　　　　　list.add(wrapper);<br />　　　　　　}<br />　　　　}<br />　　　　if (list.size() == 0) {<br />　　　　　　return null;<br />　　　　}<br />　　　　wrapper = (ConnectionWrapper) list.removeFirst();<br />　　　　m_usedUsedConnection.add(wrapper);<br /><br />　　　　m_notUsedConnection.addAll(list);<br />　　　　list.clear();<br /><br />　　　　return wrapper.connection;<br />　　}<br /><br />　　private static ConnectionWrapper getNewConnection() {<br />　　　　try {<br />　　　　　　Connection con = DriverManager.getConnection(m_url, m_user, m_password);<br />　　　　　　ConnectionWrapper wrapper = new ConnectionWrapper(con);<br />　　　　　　return wrapper;<br />　　　　} catch (Exception e) {<br />　　　　　　e.printStackTrace();<br />　　　　}<br />　　　　return null;<br />　　}<br /><br />　　static synchronized void pushConnectionBackToPool(ConnectionWrapper con) {<br />　　　　boolean exist = m_usedUsedConnection.remove(con);<br />　　　　if (exist) {<br />　　　　　　m_notUsedConnection.addLast(con);<br />　　　　}<br />　　}<br /><br />　　public static int close() {<br />　　　　int count = 0;<br /><br />　　　　Iterator iterator = m_notUsedConnection.iterator();<br />　　　　while (iterator.hasNext()) {<br />　　　　　　try {<br />　　　　　　　　( (ConnectionWrapper) iterator.next()).close();<br />　　　　　　　　count++;<br />　　　　　　} catch (Exception e) {<br />　　　　　　}<br />　　　　}<br />　　　　m_notUsedConnection.clear();<br /><br />　　　　iterator = m_usedUsedConnection.iterator();<br />　　　　while (iterator.hasNext()) {<br />　　　　　　try {<br />　　　　　　　　ConnectionWrapper wrapper = (ConnectionWrapper) iterator.next();<br />　　　　　　　　wrapper.close();<br />　　　　　　　　if (DEBUG) {<br />　　　　　　　　　　wrapper.debugInfo.printStackTrace();<br />　　　　　　　　}<br />　　　　　　　　count++;<br />　　　　　　} catch (Exception e) {<br />　　　　　　}<br />　　　　}<br />　　　　m_usedUsedConnection.clear();<br /><br />　　　　return count;<br />　　}<br /><br />　　private static void clearClosedConnection() {<br />　　　　long time = System.currentTimeMillis();<br />　　　　//sometimes user change system time,just return<br />　　　　if (time &lt; m_lastClearClosedConnection) {<br />　　　　　　time = m_lastClearClosedConnection;<br />　　　　　　return;<br />　　　　}<br />　　　　//no need check very often<br />　　　　if (time - m_lastClearClosedConnection &lt; CHECK_CLOSED_CONNECTION_TIME) {<br />　　　　　　return;<br />　　　　}<br />　　　　m_lastClearClosedConnection = time;<br /><br />　　　　//begin check<br />　　　　Iterator iterator = m_notUsedConnection.iterator();<br />　　　　while (iterator.hasNext()) {<br />　　　　　　ConnectionWrapper wrapper = (ConnectionWrapper) iterator.next();<br />　　　　　　try {<br />　　　　　　　　if (wrapper.connection.isClosed()) {<br />　　　　　　　　　　iterator.remove();<br />　　　　　　　　}<br />　　　　　　} catch (Exception e) {<br />　　　　　　　　iterator.remove();<br />　　　　　　　　if (DEBUG) {<br />　　　　　　　　　　System.out.println("connection is closed, this connection initial StackTrace");<br />　　　　　　　　　　wrapper.debugInfo.printStackTrace();<br />　　　　　　　　}<br />　　　　　　}<br />　　　　}<br /><br />　　　　//make connection pool size smaller if too big<br />　　　　int decrease = getDecreasingConnectionCount();<br />　　　　if (m_notUsedConnection.size() &lt; decrease) {<br />　　　　　　return;<br />　　　　}<br /><br />　　　　while (decrease-- &gt; 0) {<br />　　　　　　ConnectionWrapper wrapper = (ConnectionWrapper) m_notUsedConnection.removeFirst();<br />　　　　　　try {<br />　　　　　　　　wrapper.connection.close();<br />　　　　　　} catch (Exception e) {<br />　　　　　　}<br />　　　　}<br />　　}<br /><br />　　/**<br />　　 * get increasing connection count, not just add 1 connection<br />　　 * @return count<br />　　 */<br />　　public static int getIncreasingConnectionCount() {<br />　　　　int count = 1;<br />　　　　int current = getConnectionCount();<br />　　　　count = current / 4;<br />　　　　if (count &lt; 1) {<br />　　　　　　count = 1;<br />　　　　}<br />　　　　return count;<br />　　}<br /><br />　　/**<br />　　 * get decreasing connection count, not just remove 1 connection<br />　　 * @return count<br />　　 */<br />　　public static int getDecreasingConnectionCount() {<br />　　　　int count = 0;<br />　　　　int current = getConnectionCount();<br />　　　　if (current &lt; 10) {<br />　　　　　　return 0;<br />　　　　}<br />　　　　return current / 3;<br />　　}<br /><br />　　public synchronized static void printDebugMsg() {<br />　　　　printDebugMsg(System.out);<br />　　}<br /><br />　　public synchronized static void printDebugMsg(PrintStream out) {<br />　　　　if (DEBUG == false) {<br />　　　　　　return;<br />　　　　}<br />　　　　StringBuffer msg = new StringBuffer();<br />　　　　msg.append("debug message in " + SimpleConnetionPool.class.getName());<br />　　　　msg.append("\r\n");<br />　　　　msg.append("total count is connection pool: " + getConnectionCount());<br />　　　　msg.append("\r\n");<br />　　　　msg.append("not used connection count: " + getNotUsedConnectionCount());<br />　　　　msg.append("\r\n");<br />　　　　msg.append("used connection, count: " + getUsedConnectionCount());<br />　　　　out.println(msg);<br />　　　　Iterator iterator = m_usedUsedConnection.iterator();<br />　　　　while (iterator.hasNext()) {<br />　　　　　　ConnectionWrapper wrapper = (ConnectionWrapper) iterator.next();<br />　　　　　　wrapper.debugInfo.printStackTrace(out);<br />　　　　}<br />　　　　out.println();<br />　　}<br /><br />　　public static synchronized int getNotUsedConnectionCount() {<br />　　　　return m_notUsedConnection.size();<br />　　}<br /><br />　　public static synchronized int getUsedConnectionCount() {<br />　　　　return m_usedUsedConnection.size();<br />　　}<br /><br />　　public static synchronized int getConnectionCount() {<br />　　　　return m_notUsedConnection.size() + m_usedUsedConnection.size();<br />　　}<br /><br />　　public static String getUrl() {<br />　　　　return m_url;<br />　　}<br /><br />　　public static void setUrl(String url) {<br />　　　　if (url == null) {<br />　　　　　　return;<br />　　　　}<br />　　　　m_url = url.trim();<br />　　}<br /><br />　　public static String getUser() {<br />　　　　return m_user;<br />　　}<br /><br />　　public static void setUser(String user) {<br />　　　　if (user == null) {<br />　　　　　　return;<br />　　　　}<br />　　　　m_user = user.trim();<br />　　}<br /><br />　　public static String getPassword() {<br />　　　　return m_password;<br />　　}<br /><br />　　public static void setPassword(String password) {<br />　　　　if (password == null) {<br />　　　　　　return;<br />　　　　}<br />　　　　m_password = password.trim();<br />　　}<br /><br />}<br /><br />class ConnectionWrapper implements InvocationHandler {<br />　　private final static String CLOSE_METHOD_NAME = "close";<br />　　public Connection connection = null;<br />　　private Connection m_originConnection = null;<br />　　public long lastAccessTime = System.currentTimeMillis();<br />　　Throwable debugInfo = new Throwable("Connection initial statement");<br /><br />　　ConnectionWrapper(Connection con) {<br />　　　　Class[] interfaces = {java.sql.Connection.class};<br />　　　　this.connection = (Connection) Proxy.newProxyInstance(<br />　　　　　　con.getClass().getClassLoader(),<br />　　　　　　interfaces, this);<br />　　　　m_originConnection = con;<br />　　}<br /><br />　　void close() throws SQLException {<br />　　　　m_originConnection.close();<br />　　}<br /><br />　　public Object invoke(Object proxy, Method m, Object[] args) throws Throwable {<br />　　　　Object obj = null;<br />　　　　if (CLOSE_METHOD_NAME.equals(m.getName())) {<br />　　　　　　SimpleConnetionPool.pushConnectionBackToPool(this);<br />　　　　}<br />　　　　else {<br />　　　　　　obj = m.invoke(m_originConnection, args);<br />　　　　}<br />　　　　lastAccessTime = System.currentTimeMillis();<br />　　　　return obj;<br />　　}<br />}</pre><br /><br />使用方法<br /><br /><pre class="overflow">public class TestConnectionPool{<br />　　public static void main(String[] args) {<br />　　　　SimpleConnetionPool.setUrl(DBTools.getDatabaseUrl());<br />　　　　SimpleConnetionPool.setUser(DBTools.getDatabaseUserName());<br />　　　　SimpleConnetionPool.setPassword(DBTools.getDatabasePassword());<br /><br />　　　　Connection con = SimpleConnetionPool.getConnection();<br />　　　　Connection con1 = SimpleConnetionPool.getConnection();<br />　　　　Connection con2 = SimpleConnetionPool.getConnection();<br /><br />　　　　//do something with con ...<br /><br />　　　　try {<br />　　　　　　con.close();<br />　　　　} catch (Exception e) {}<br /><br />　　　　try {<br />　　　　　　con1.close();<br />　　　　} catch (Exception e) {}<br /><br />　　　　try {<br />　　　　　　con2.close();<br />　　　　} catch (Exception e) {}<br /><br />　　　　con = SimpleConnetionPool.getConnection();<br />　　　　con1 = SimpleConnetionPool.getConnection();<br />　　　　try {<br />　　　　　　con1.close();<br />　　　　} catch (Exception e) {}<br /><br />　　　　con2 = SimpleConnetionPool.getConnection();<br />　　　　SimpleConnetionPool.printDebugMsg();<br /><br />　　}<br />}</pre><img src ="http://www.blogjava.net/machilansing/aggbug/61776.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/machilansing/" target="_blank">Lansing</a> 2006-08-04 15:56 <a href="http://www.blogjava.net/machilansing/archive/2006/08/04/61776.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item></channel></rss>