<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>OurApache &#187; common-dbcp</title>
	<atom:link href="http://ourapache.com/archives/tag/common-dbcp/feed" rel="self" type="application/rss+xml" />
	<link>http://ourapache.com</link>
	<description>我们致力于一个Apache知识的分享网站</description>
	<lastBuildDate>Tue, 13 Apr 2010 05:18:24 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.2.1</generator>
		<item>
		<title>Apache common-pool, common-dbcp源码解读与对象池原理剖析</title>
		<link>http://ourapache.com/archives/211</link>
		<comments>http://ourapache.com/archives/211#comments</comments>
		<pubDate>Fri, 27 Feb 2009 11:24:08 +0000</pubDate>
		<dc:creator>OurApache</dc:creator>
				<category><![CDATA[Apache高级应用]]></category>
		<category><![CDATA[common-dbcp]]></category>
		<category><![CDATA[common-pool]]></category>
		<category><![CDATA[对象池]]></category>

		<guid isPermaLink="false">http://www.ourapache.com/?p=211</guid>
		<description><![CDATA[最近在做一个内部测试工具类的优化工作中接触到了连接池, 对象池技术, 将原有的未使用连接池的数据库访问操作改成连接池方式.性能有了非常大的提升, 事实证明, 经过两次改造, 原来一个比较大的测试类需要500多秒, 第一次优化后只需要300多秒, 第二次改用连接池之后同一个测试类只需要80多秒.下面是改造过程中的一些总结.
对象池就是以”空间换时间”的 一种常用缓存机制, 这里的”时间”特指创建时间,因此这也给出了对象池的适用范围:如果一种对象的创建过程非常耗时的话, 那么请使用对象池. 内部原理简单的说, 就是将创建的对象放到一个容器中, 用完之后不是销毁而是再放回该容器, 让其他的对象调用, 对象池中还涉及到一些高级的技术, 比如过期销毁, 被破坏时销毁, 对象数超过池大小销毁, 对象池中没有可用空闲对象时等待等等.]]></description>
			<content:encoded><![CDATA[<p><span>最近在做一个内部测试工具类的优化工作中接触到了连接池, 对象池技术, 将原有的未使用连接池的数据库访问操作改成连接池方式.性能有了非常大的提升, 事实证明, 经过两次改造, 原来一个比较大的测试类需要500多秒, 第一次优化后只需要300多秒, 第二次改用连接池之后同一个测试类只需要80多秒.下面是改造过程中的一些总结.<br />
对象池就是以”空间换时间”的 一种常用缓存机制, 这里的”时间”特指创建时间,因此这也给出了对象池的适用范围:如果一种对象的创建过程非常耗时的话, 那么请使用对象池. 内部原理简单的说, 就是将创建的对象放到一个容器中, 用完之后不是销毁而是再放回该容器, 让其他的对象调用, 对象池中还涉及到一些高级的技术, 比如过期销毁, 被破坏时销毁, 对象数超过池大小销毁, 对象池中没有可用空闲对象时等待等等.</span></p>
<p>apache的common-pool工具库是对池化技术原理的一种具体实现. 在阐述原来之前, 这里先理解几个概念:<br />
<strong><a href="http://ourapache.com/archives/tag/%e5%af%b9%e8%b1%a1%e6%b1%a0" class="st_tag internal_tag" rel="tag" title="标签 对象池 下的日志">对象池</a></strong>(ObjectPool接口): 可以把它认为是一种容器, 它是用来装池对象的, 并且包含了用来创建池对象的工厂对象<br />
<strong>池对象</strong>:就是要放到池容器中的对象, 理论上可以是任何对象.<br />
<strong>对象池工厂</strong>(ObjectPoolFactory接口):用来创建对象池的工厂, 这个没什么好说的.<br />
<strong>池对象工厂</strong>(PoolableObjectFactory 接口):用来创建池对象, 将不用的池对象进行钝化(passivateObject), 对要使用的池对象进行激活(activeObject), 对池对象进行验证(validateObject), 对有问题的池对象进行销毁(destroyObject)等工作</p>
<p>对象池中封装了创建, 获取, 归还, 销毁池对象的职责, 当然这些工作都是通过池对象工厂来实施的, 容器内部还有一个或多个用来盛池对象的容器.对象池会对容器大小, 存放时间, 访问等待时间, 空闲时间等等进行一些控制, 因为可以根据需要来调整这些设置.</p>
<p>当 需要拿一个池对象的时候, 就从容器中取出一个, 如果容器中没有的话, 而且又没有达到容器的最大限制, 那么就调用池对象工厂, 新建一个池对象, 并调用工厂的激活方法, 对创建的对象进行激活, 验证等一系列操作. 如果已经达到池容器的最大值, 而对象池中又经没有空闲的对象, 那么将会继续等待, 直到有新的空闲的对象被丢进来, 当然这个等待也是有限度的, 如果超出了这个限度, 对象池就会抛出异常.</p>
<p>“出来 混, 总是要还的”, 池对象也是如此, 当将用完的池对象归还到对象池中的时候, 对象池会调用池对象工厂对该池对象进行验证, 如果验证不通过则被认为是有问题的对象, 将会被销毁, 同样如果容器已经满了, 这个归还池对象将变的”无家可归”, 也会被销毁, 如果不属于上面两种情况, 对象池就会调用工厂对象将其钝化并放入容器中. 在整个过程中, 激活, 检查, 钝化处理都不是必须的, 因此我们在实现PoolableObjectFactory接口的时候, 一般不作处理, 给空实现即可, 所以诞生了BasePoolableObjectFactory.</p>
<p>当然你也可以将要已有的对象创建好, 然后通过addObject放到对象池中去, 以备后用.</p>
<p>为了确保对对象池的访问都是线程安全的, 所有对容器的操作都必须放在synchronized中.</p>
<p>在 apache的common-pool工具库中有5种对象池:GenericObjectPool和 GenericKeyedObjectPool, SoftReferenceObjectPool, StackObjectPool, StackKeyedObjectPool.<br />
五种对象池可分为两类, 一类是无key的:</p>
<p><span><img class="alignnone size-full wp-image-212" title="1" src="http://www.ourapache.com/wp-content/uploads/2009/02/1.gif" alt="1" width="673" height="557" /><br />
</span></p>
<p>另一类是有key的:</p>
<p><img class="alignnone size-full wp-image-213" title="2" src="http://www.ourapache.com/wp-content/uploads/2009/02/2.gif" alt="2" width="749" height="582" /></p>
<p>前面两种用CursorableLinkedList来做容器, SoftReferenceObjectPool用ArrayList做容器, 一次性创建所有池化对象, 并对容器中的对象进行了软引用(SoftReference)处理, 从而保证在内存充足的时候池对象不会轻易被jvm垃圾回收, 从而具有很强的缓存能力. 最后两种用Stack做容器. 不带key的对象池是对前面池技术原理的一种简单实现, 带key的相对复杂一些, 它会将池对象按照key来进行分类, 具有相同的key被划分到一组类别中, 因此有多少个key, 就会有多少个容器. 之所以需要带key的这种对象池, 是因为普通的对象池通过makeObject()方法创建的对象基本上都是一模一样的, 因为没法传递参数来对池对象进行定制. 因此四种池对象的区别主要体现在内部的容器的区别, Stack遵循”后进先出”的原则并能保证线程安全, CursorableLinkedList是一个内部用游标(cursor)来定位当前元素的双向链表, 是非线程安全的, 但是能满足对容器的并发修改.ArrayList是非线程安全的, 便利方便的容器.</p>
<p>使用对象池的一般步骤:创建一个池对象工厂, 将该工厂注入到对象池中, 当要取池对象, 调用borrowObject, 当要归还池对象时, 调用returnObject, 销毁池对象调用clear(), 如果要连池对象工厂也一起销毁, 则调用close().<br />
下面是一些时序图:<br />
borrowObject:</p>
<p><img class="alignnone size-full wp-image-214" title="3" src="http://www.ourapache.com/wp-content/uploads/2009/02/3.gif" alt="3" width="405" height="251" /></p>
<p>returnObject:</p>
<p><img class="alignnone size-full wp-image-215" title="4" src="http://www.ourapache.com/wp-content/uploads/2009/02/4.gif" alt="4" width="428" height="206" /></p>
<p>invalidateObject:</p>
<p><img class="alignnone size-full wp-image-217" title="51" src="http://www.ourapache.com/wp-content/uploads/2009/02/51.gif" alt="51" width="457" height="126" /></p>
<p>apache的连接池工具库common-dbcp是common-pool在数据库访问方面的一个具体应用.当对common-pool熟悉之后, 对common-dbcp就很好理解了. 它通过对已有的Connection, Statment对象包装成池对象PoolableConnection, PoolablePreparedStatement. 然后在这些池化的对象中, 持有一个对对象池的引用, 在关闭的时候, 不进行真正的关闭处理, 而是通过调用:<br />
<code>1. _pool.returnObject(this); </code><br />
或:<br />
<code>1. _pool.returnObject(_key,this); </code><br />
这样一句, 将连接对象放回连接池中.<br />
而对应的对象池前者采用的是ObjectPool, 后者是KeyedObjectPool, 因为一个数据库只对应一个连接, 而执行操作的Statement却根据Sql的不同会分很多种. 因此需要根据sql语句的不同多次进行缓存<br />
在对连接池的管理上, common-dbcp主要采用两种对象:<br />
一个是PoolingDriver, 另一个是PoolingDataSource, 二者的区别是PoolingDriver是一个更底层的操作类, 它持有一个连接池映射列表, 一般针对在一个jvm中要连接多个数据库, 而后者相对简单一些. 内部只能持有一个连接池, 即一个数据源对应一个连接池.<br />
下面是common-dbcp的结构关系:</p>
<p><span><img class="alignnone size-full wp-image-218" title="6" src="http://www.ourapache.com/wp-content/uploads/2009/02/6.gif" alt="6" width="912" height="547" /></span></p>
<p>下面是参考了common-dbcp的例子之后写的一个从连接池中获取连接的工具类</p>
<blockquote><p>1. /**<br />
2. * 创建连接<br />
3. *<br />
4. * @since 2009-1-22 下午02:58:35<br />
5. */<br />
6. public class ConnectionUtils {<br />
7. // 一些common-dbcp内部定义的protocol<br />
8. private static final String POOL_DRIVER_KEY = “jdbc:apache:commons:dbcp:”;<br />
9. private static final String POLLING_DRIVER = “org.apache.commons.dbcp.PoolingDriver”;<br />
10.<br />
11. /**<br />
12. * 取得池化驱动器<br />
13. *<br />
14. * @return<br />
15. * @throws ClassNotFoundException<br />
16. * @throws SQLException<br />
17. */<br />
18. private static PoolingDriver getPoolDriver() throws ClassNotFoundException,<br />
19. SQLException {<br />
20. Class.forName(POLLING_DRIVER);<br />
21. return (PoolingDriver) DriverManager.getDriver(POOL_DRIVER_KEY);<br />
22. }<br />
23.<br />
24. /**<br />
25. * 销毁所有连接<br />
26. *<br />
27. * @throws Exception<br />
28. */<br />
29. public static void destory() throws Exception {<br />
30. PoolingDriver driver = getPoolDriver();<br />
31. String[] names = driver.getPoolNames();<br />
32. for (String name : names) {<br />
33. driver.getConnectionPool(name).close();<br />
34. }<br />
35. }<br />
36.<br />
37. /**<br />
38. * 从连接池中获取数据库连接<br />
39. */<br />
40. public static Connection getConnection(TableMetaData table)<br />
41. throws Exception {<br />
42. String key = table.getConnectionKey();<br />
43.<br />
44. PoolingDriver driver = getPoolDriver();<br />
45.<br />
46. ObjectPool pool = null;<br />
47. // 这里找不到连接池会抛异常, 需要catch一下<br />
48. try {<br />
49. pool = driver.getConnectionPool(key);<br />
50. } catch (Exception e) {<br />
51. }<br />
52.<br />
53. if (pool == null) {<br />
54. // 根据数据库类型构建连接工厂<br />
55. ConnectionFactory connectionFactory = null;<br />
56. if (table.getDbAddr() != null<br />
57. &amp;&amp; TableMetaData.DB_TYPE_MYSQL == table.getDbType()) {<br />
58. Class.forName(TableMetaData.MYSQL_DRIVER);<br />
59. connectionFactory = new DriverManagerConnectionFactory(table<br />
60. .getDBUrl(), null);<br />
61. } else {<br />
62. Class.forName(TableMetaData.ORACLE_DRIVER);<br />
63. connectionFactory = new DriverManagerConnectionFactory(table<br />
64. .getDBUrl(), table.getDbuser(), table.getDbpass());<br />
65. }<br />
66.<br />
67. // 构造连接池<br />
68. ObjectPool connectionPool = new GenericObjectPool(null);<br />
69. new PoolableConnectionFactory(connectionFactory, connectionPool,<br />
70. null, null, false, true);<br />
71.<br />
72. // 将连接池注册到driver中<br />
73. driver.registerPool(key, connectionPool);<br />
74. }<br />
75.<br />
76. // 从连接池中拿一个连接<br />
77. return DriverManager.getConnection(POOL_DRIVER_KEY + key);<br />
78. }<br />
79.<br />
80. }</p></blockquote>
<p>虽然对象池技术在实际开发过程中用的不是很多, 但是理解之后对我们写程序还是有莫大的好处的, 至少我是这样的</p>
<h3  class="related_post_title">无相关文章，以下随机显示</h3><ul class="related_post"><li>2009年01月22号 -- <a href="http://ourapache.com/archives/68" title="apache最大连接数性能测试">apache最大连接数性能测试</a></li><li>2009年12月12号 -- <a href="http://ourapache.com/archives/310" title=".htaccess的301跳转">.htaccess的301跳转</a></li><li>2008年12月27号 -- <a href="http://ourapache.com/archives/11" title="apxs &#8211; Apache 扩展工具">apxs &#8211; Apache 扩展工具</a></li><li>2009年02月25号 -- <a href="http://ourapache.com/archives/176" title="网站服务器(Apache)的日志与监视">网站服务器(Apache)的日志与监视</a></li><li>2009年07月14号 -- <a href="http://ourapache.com/archives/263" title="初识HTTP中的Referer">初识HTTP中的Referer</a></li><li>2009年02月27号 -- <a href="http://ourapache.com/archives/190" title="header Content-Disposition参数说明">header Content-Disposition参数说明</a></li><li>2009年02月7号 -- <a href="http://ourapache.com/archives/87" title="Linux下查看apache连接数">Linux下查看apache连接数</a></li><li>2009年02月7号 -- <a href="http://ourapache.com/archives/94" title="使用gzip压缩来压缩网页之apache的相关配置">使用gzip压缩来压缩网页之apache的相关配置</a></li><li>2009年06月1号 -- <a href="http://ourapache.com/archives/243" title="玩转apache之日志">玩转apache之日志</a></li><li>2009年02月18号 -- <a href="http://ourapache.com/archives/146" title="apache和tomcat集成的总结">apache和tomcat集成的总结</a></li></ul>
	标签：<a href="http://ourapache.com/archives/category/advanced" title="Apache高级应用" rel="tag">Apache高级应用</a>, <a href="http://ourapache.com/archives/tag/common-dbcp" title="common-dbcp" rel="tag">common-dbcp</a>, <a href="http://ourapache.com/archives/tag/common-pool" title="common-pool" rel="tag">common-pool</a>, <a href="http://ourapache.com/archives/tag/%e5%af%b9%e8%b1%a1%e6%b1%a0" title="对象池" rel="tag">对象池</a><br />
]]></content:encoded>
			<wfw:commentRss>http://ourapache.com/archives/211/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
	</channel>
</rss>

