Topic: 连接池是否有用? |
Print this page |
1.连接池是否有用? | Copy to clipboard |
Posted by: jackzhuo Posted on: 2003-09-04 16:30 我们最近在做一个项目,其中对数据库的连接,我们使用了池的技术,但在使用中由于数据库的压力比较大,所以在对数据库进行操作时经常取不到连接,千万交易处理特别慢,有时对取得连接对数据库操作,一个SQL语句要用10几秒钟,找了很长时间原因都没有找到. 昨天晚上,由于公司的压力比较大,加了一晚上的班(程序员的痛苦与快乐),终于定位到是池调度太慢的问题,于是我们就对此进行了修改,修改的连我自己都不得觉得奇怪,但是居然效果还可以!!!! 我们在启动时去掉了池的基本策略,即先启动一个最小数,我们启动了一个值,最小值和最大值定为相同值,然后在使用中每个线程(在我们的应用中可能会同时有200-300个线程一同对数据库进行操作)随机地从预先打开的池中取出一个连接(与池不同的是,不管该连接是否已经在用,都会取到相应的连接),然后就象平时一样的使用,即生成一个新的statement,发出SQL命令等等,使用完成后并不需要做connection的close操作,而原来的池管理器只是在当连接出现问题时重新建立一个新的连接并将它放到连接Vector中,并没有做什么特别的操作,但是居然运行性能非常好,现在(今天早上刚换上版,还没有出现什么问题,一晚上总算没有白过). 刚睡觉起来还没有去查一些资料,先和大家分享一下这个经验,当然也希望大家都能发表一下自己的看法,如果真是这样的话.连接池还有什么用? |
2.Re:连接池是否有用? [Re: jackzhuo] | Copy to clipboard |
Posted by: faint Posted on: 2003-09-09 16:23 你使用的连接池是否是第三方实现的(JDBC Driver实现,Application Server实现),还是自己实现的,你后面的说的不太清楚,能详细点说明吗? |
3.Re:连接池是否有用? [Re: jackzhuo] | Copy to clipboard |
Posted by: sharedata Posted on: 2003-09-09 18:43 关心这个问题,jackzhuo 可否说详细些:因为一般的我们没有那么大的模拟数据量很难发现一些细节问题。我自己最近也准备改写一些连接池的实现,所以很关心这个。 |
4.Re:连接池是否有用? [Re: jackzhuo] | Copy to clipboard |
Posted by: runaway Posted on: 2003-09-10 10:30 如果是前端与后端保持固定的连接,而且前端数量不大,没有必要使用连接池,尤其是长时间保持连接的情况,否则只有副作用。 连接池适用于需要频繁的连接与断开操作的场合。 |
5.Re:连接池是否有用? [Re: faint] | Copy to clipboard |
Posted by: jackzhuo Posted on: 2003-09-10 15:43 我查过Oracle中OraclePooleddataSource的实现代码,发现在这个代码中没有实现池的功能(很简单的一点,你如果使用这个类的话,根本没有地方去设置池的最小值和最大值,而这两个参数基本上是池的最基本的参数),昨天和Borland的一个工程师聊起此事,又看了一下Oracle的代码,最后觉得对于数据库本身实现的池似乎并没有完全实现,而只能和Appication Server结合在一起时,才能真正有池的功能,如果你没有Application Server的配合的话,则数据库本身的池似乎都没有用. 象我在第一点说的,我们的做法是不使用池调度,当需要连接时,不管此连接是否在用都分配给它用,这各做法在我们现在的实现中是可以用的,因为我们现在的数据库操作中基本都没有用到事务,而Oracle驱动程序对Connection类和Statement两个类中的对数据库进行具体操作的方法全部是同步方法,所以现在用起来没有问题!但是如果要使用事务的话,这种方法就不能用了. 我们现在准备使用Apache的DBCP来做池管理器,并且也进行了一些测试,性能还不错,使用起来也比较简单,最大的好处是开源,有什么问题可以看看源代码,哈哈. 以上是我的一些经验,希望多多交流! |
6.Re:连接池是否有用? [Re: jackzhuo] | Copy to clipboard |
Posted by: faint Posted on: 2003-09-10 18:58 jackzhuo wrote: 在oracle的type4驱动中oracle.jdbc.pool.OracleConnectionCacheImpl是Oracle连接池的实现,OraclePooleddataSource继承于OracleDataSource,而OracleDataSource中有连接池初始值设定属性。Oracle连接池的实现是根据JDBC3.0规范中连接池框架实现的,具体内容可以看规范。 连接池的实现根据我看到的情况分为了三种:Driver实现,Application Server实现,自己实现。如果从理论的角度上来说应该推荐使用Application Server实现的连接池,因为可以通过Application Server来管理数据库连接。使用DBCP应该可以理解为自己实现(不是太确定,如果有兄弟有疑问请指出)。 |
7.Re:连接池是否有用? [Re: jackzhuo] | Copy to clipboard |
Posted by: jackzhuo Posted on: 2003-09-12 23:26 是我没有看的深入,其实Oracle实现池的类名字是OracleConnectionCacheImpl,它的父类是OracleDataSource,再上一层的基本接口是Djavax.sql.DataSource. 如果要使用池的话,就必须使用OracleConnectionCacheImpl,共有三种池的策略: DYNAMIC_SCHEME The cache will create connections above the specified maximum limit when necessary but will in turn close connections as they are returned to the cache until the number of connections is within the maximum limit. Connections will never be cached above the maximum limit. This is the default setting. FIXED_RETURN_NULL_SCHEME The cache will return a null connection once the maximum connection limit has been exceeded. FIXED_WAIT_SCHEME The cache will wait until there is a connection available and will then return it to the calling application. 它还提供了几个设置池参数的方法: public void setCacheScheme(int cacheScheme); public void setMinLimit(int minCacheSize); public void setMaxLimit(int maxCacheSize); 而OracleConnectionCacheImpl在具体的使用上需要和ConnectionPoolDataSource配合,下面就是一个例子. |
8.Re:连接池是否有用? [Re: jackzhuo] | Copy to clipboard |
Posted by: jackzhuo Posted on: 2003-09-12 23:30 首先生成一个ConnectionPoolDataSource对象的实例并且设置相应的参数,然后绪定JNDI服务器中. import java.sql.*; import java.util.*; import javax.naming.*; import oracle.jdbc.pool.*; public class OCCIBind { public static void main (String args []) throws SQLException, NamingException { Context context = null; try { Properties properties = new Properties( ); properties.setProperty( Context.INITIAL_CONTEXT_FACTORY, "com.sun.jndi.fscontext.RefFSContextFactory"); properties.setProperty( Context.PROVIDER_URL, "file:/JNDI/JDBC"); context = new InitialContext(properties); } catch (NamingException ne) { System.err.println(ne.getMessage( )); } OracleConnectionPoolDataSource ocpds = new OracleConnectionPoolDataSource( ); ocpds.setDescription("Database"); ocpds.setDriverType("thin"); ocpds.setServerName("dssw2k01"); ocpds.setPortNumber(1521); ocpds.setDatabaseName("orcl"); ocpds.setUser("scott"); ocpds.setPassword("tiger"); context.bind(ocpds.getDescription( ), ocpds); } |
9.Re:连接池是否有用? [Re: jackzhuo] | Copy to clipboard |
Posted by: jackzhuo Posted on: 2003-09-12 23:33 然后按下面的方法进行使用(注意黑体字的部分): import java.io.*; import java.sql.*; import java.util.*; import javax.naming.*; import javax.sql.*; import oracle.jdbc.pool.*; public class OCCIConnection { private static boolean verbose = false; private static int numberImplementations = 0; private static Vector cachedImplementations = new Vector( ); public synchronized static Connection checkOut( ) { return checkOut("Database"); } public synchronized static Connection checkOut(String baseName) { boolean found = false; OracleConnectionCacheImpl cached = null; Connection connection = null; if (verbose) { System.out.println("There are " + Integer.toString(numberImplementations) + " connections in the cache"); System.out.println("Searching for a matching implementation..."); } for (int i=0;!found && i<numberImplementations;i++) { if (verbose) { System.out.println("Vector entry " + Integer.toString(i)); } cached = (OracleConnectionCacheImpl)cachedImplementations.get(i); if (cached.getDescription( ).equals(baseName)) { if (verbose) { System.out.println("found cached entry " + Integer.toString(i) + " for " + baseName); } found = true; } } if (!found) { if (verbose) { System.out.println("Cached entry not found "); System.out.println("Allocating new entry for " + baseName); } try { [b]cached = new OracleConnectionCacheImpl(getConnectionPoolDataSource(baseName));[/b] cached.setDescription(baseName); cachedImplementations.add(cached); numberImplementations++; } catch (SQLException e) { System.err.println(e.getMessage( ) + " creating a new implementation for " + baseName); } } if (cached != null) { try { connection = cached.getConnection( ); } catch (SQLException e) { System.err.println(e.getMessage( ) + " getting connection for " + baseName); } } return connection; } public static ConnectionPoolDataSource getConnectionPoolDataSource(String baseName) { Context context = null; ConnectionPoolDataSource cpds = null; try { Properties properties = new Properties( ); properties.setProperty( Context.INITIAL_CONTEXT_FACTORY, "com.sun.jndi.fscontext.RefFSContextFactory"); properties.setProperty( Context.PROVIDER_URL, "file:/JNDI/JDBC"); context = new InitialContext(properties); cpds = (ConnectionPoolDataSource)context.lookup(baseName); } catch (NamingException e) { System.err.println(e.getMessage( ) + " creating JNDI context for " + baseName); } return cpds; } protected static synchronized void checkIn(Connection c) { try { c.close( ); } catch (SQLException e) { System.err.println(e.getMessage( ) + " closing connection"); } } public static String[] getReport( ) { int line = 0; String[] lines = new String[numberImplementations * 7]; OracleConnectionCacheImpl cached = null; for (int i=0;i < numberImplementations;i++) { cached = (OracleConnectionCacheImpl)cachedImplementations.get(i); lines[line++] = cached.getDescription( ) + ":"; switch (cached.getCacheScheme( )) { case OracleConnectionCacheImpl.DYNAMIC_SCHEME: lines[line++] = "Cache Scheme = DYNAMIC_SCHEME"; break; case OracleConnectionCacheImpl.FIXED_RETURN_NULL_SCHEME: lines[line++] = "Cache Scheme = FIXED_RETURN_NULL_SCHEME"; break; case OracleConnectionCacheImpl.FIXED_WAIT_SCHEME: lines[line++] = "Cache Scheme = FIXED_WAIT_SCHEME"; break; } lines[line++] = "Minimum Limit = " + Integer.toString(cached.getMinLimit( )); lines[line++] = "Maximum Limit = " + Integer.toString(cached.getMaxLimit( )); lines[line++] = "Cache Size = " + Integer.toString(cached.getCacheSize( )); lines[line++] = "Active Size = " + Integer.toString(cached.getActiveSize( )); lines[line++] = " "; } return lines; } public static void setVerbose(boolean v) { verbose = v; } } |
10.Re:连接池是否有用? [Re: jackzhuo] | Copy to clipboard |
Posted by: jackzhuo Posted on: 2003-09-12 23:35 这个例子是从<Java Programming with Oracle JDBC>一书上节选下来的,有兴趣大家可能去看一下这本书! 也希望我上面写的对大家能有所帮助! |
11.Re:连接池是否有用? [Re: jackzhuo] | Copy to clipboard |
Posted by: floater Posted on: 2003-09-13 00:49 how many connections in the pool? |
12.Re:连接池是否有用? [Re: jackzhuo] | Copy to clipboard |
Posted by: jackzhuo Posted on: 2003-09-14 14:25 以下是节选自oracle.jdbc.pool.OracleConnectionCacheImpl的代码: private static int _DEFAULT_MIN_LIMIT = 0; private static int _DEFAULT_MAX_LIMIT = 10; public static final int DYNAMIC_SCHEME = 1; |
13.Re:连接池是否有用? [Re: jackzhuo] | Copy to clipboard |
Posted by: floater Posted on: 2003-09-19 00:40 Sorry, I didn't say it right. I mean how many active connections in the pool in production where you have tons of threads coming in. Naturally, you print out the number of active connections to the log and monitor from there. Oracle is always a little(not much) diff from others, . |
14.Re:连接池是否有用? [Re: jackzhuo] | Copy to clipboard |
Posted by: runaway Posted on: 2003-09-20 18:01 应该是有多少连接会同时使用连接池,如果不超过100个,建议还是不要用连接池的好,Oracle完全有能力处理这些连接,池管理总是需要一些代价的。 |
15.Re:连接池是否有用? [Re: runaway] | Copy to clipboard |
Posted by: floater Posted on: 2003-09-20 22:08 runaway wrote: ignorable. |
16.Re:连接池是否有用? [Re: runaway] | Copy to clipboard |
Posted by: jackzhuo Posted on: 2003-09-22 17:50 runaway wrote: 我不这么看,100个连接是一件很奢侈的东西,我们现在的连接是30个,使用池并不是就多少个连接以上才能使用的,象我们现在的应用,每天几万笔交易,在同一时刻可能会有几千个请求一起在处理,数据库资源肯定是有限的,在这个时候就最好要使用池进行调度才能比较有效! |
17.Re:连接池是否有用? [Re: floater] | Copy to clipboard |
Posted by: jackzhuo Posted on: 2003-09-22 17:55 floater wrote: 可能我还是没有懂你的意思,但我写上面的贴子只是为了想和大家交流一下使用数据库连接池的经验,我原来以为ORACLE并没有实现池,其它并不是那样,现在虽然我知道它实现了池,但我还是不想用,因为我在设计时的一个初衷就是尽可能不要与具体的数据库实现相关,所以我还是想用第三方的POOL(如DBCP等).另外,现在我正在学习Hibernate,如果用了它其它都不是什么问题了! |
18.Re:连接池是否有用? [Re: jackzhuo] | Copy to clipboard |
Posted by: runaway Posted on: 2003-09-25 09:41 多层结构的一个好处是你可以选择在任何一层实现像连接池这样的东西,你完全可以根据自己的需要和具体的实现把池的功能实现在系统中。 |
19.Re:连接池是否有用? [Re: jackzhuo] | Copy to clipboard |
Posted by: lemon2000 Posted on: 2003-09-29 11:25 我们使用自己写的连接池,30个连接,几万笔交易,正常使用半年了 |
20.Re:连接池是否有用? [Re: jackzhuo] | Copy to clipboard |
Posted by: dingligang Posted on: 2003-12-17 19:32 然后在使用中每个线程(在我们的应用中可能会同时有200-300个线程一同对数据库进行操作)随机地从预先打开的池中取出一个连接(与池不同的是,不管该连接是否已经在用,都会取到相应的连接),然后就象平时一样的使用,即生成一个新的statement,发出SQL命令等等,使用完成后并不需要做connection的close操作,而原来的池管理器只是在当连接出现问题时重新建立一个新的连接并将它放到连接Vector中,并没有做什么特别的操作,但是居然运行性能非常好,现在(今天早上刚换上版,还没有出现什么问题,一晚上总算没有白过). 连接池机制中连接的分配和回收这个过程肯定涉及到同步问题,所以相对你的方法来说肯定要牺牲比较大的性能。如果你的数据库操作不涉及到事务等SQL的一系列特性,那当然没有问题,但是如果你要使用事务等,那你的方法就无能为力了(当然你可以指定一系列的连接只用于事务,因为事务要求独占一个连接)。而且数据库运行时始终要为你提供最大限度的连接数(可能数据库还为别的系统服务)。当然在特定的系统中,你的解决方案也不失为一种好方法 我的疑问是连接池真的无法满足你的开发需要了吗? |
21.Re:连接池是否有用? [Re: jackzhuo] | Copy to clipboard |
Posted by: 九佰 Posted on: 2003-12-18 09:14 最近也是项目需要,开始关注连接池。 有一个XAPool,希望对大家有帮助 这是一个开源的项目 http://xapool.experlog.com |
22.Re:连接池是否有用? [Re: dingligang] | Copy to clipboard |
Posted by: jackzhuo Posted on: 2003-12-19 22:29 dingligang wrote: 不是说连接池不能符合我的开发需要,这个贴子是我加了一个通宵后,想不通才写的(看来没有睡觉是不行呀!).其实道理和你说的一样,后来我也想通了,我们采用的做法,在没有事务处理时,也就是JDBC的AutoCommit设置为true的时候这样用也没有问题,但如果使用事务的话,就肯定不行了. 其实我现在的项目中还是使用的数据库连接池,我们使用的是Apache的DBCP,挺好用的. |
23.Re:连接池是否有用? [Re: jackzhuo] | Copy to clipboard |
Posted by: dingligang Posted on: 2003-12-21 14:04 good luck |
24.Re:连接池是否有用? [Re: jackzhuo] | Copy to clipboard |
Posted by: zane Posted on: 2003-12-30 14:14 看来了你们谈的内容,呵呵,我先说一下,你们说的这个连接池,在 oracle中对应的是shared_pool 不过知道大家知道SGA嘛?db buffers就是SGA的一部分,oracle里边还有 shared_pool,还有relog buffer SQL> show sga Total System Global Area 235999352 bytes Fixed Size 450680 bytes Variable Size 201326592 bytes Database Buffers 33554432 bytes Redo Buffers 667648 bytes 看见了吧,那个database buffers包括你们说的那个连接池。 而进行sql,cursor这些分析,Library Cache必须要用到share_pool, db buffers又有三个部分BUFFER_POOL { KEEP | RECYCLE | DEFAULT} SQL> show parameter pool NAME TYPE VALUE ------------------------------------ ----------- ------------------------------ buffer_pool_keep string buffer_pool_recycle string global_context_pool_size string java_pool_size big integer 83886080 large_pool_size big integer 16777216 olap_page_pool_size integer 33554432 shared_pool_reserved_size big integer 4194304 shared_pool_size big integer 83886080 我这里的前两个可以看打了吧,一个keep是用来放置经常使用的数据块的,recycle是可以用来放一些,经常变的。还有一个default,DEFAULT: The pool always exists. It is equivalent to the single buffer cache. 速度快的原因是keep大小设置比较合理 1* select name,block_size,buffers from v$buffer_pool SQL> / NAME BLOCK_SIZE BUFFERS -------------------- ---------- ---------- DEFAULT 8192 4004 我这个是没有进行设置的。 因为: SQL> select 8192*4004 from dual; 8192*4004 ---------- 32800768 -- 33554432 比较 和我刚才那个SGA的database buffer大小33554432差不多,就是还有没有进行优化,呵呵~~~ btw:如果有什么错误的地方请指教~~ |
25.Re:连接池是否有用? [Re: jackzhuo] | Copy to clipboard |
Posted by: faint Posted on: 2003-12-30 20:08 JavaOne 2003就有关于连接池是否有用的讲座。今天看developworks看到有人把这部分的东西翻译出来了,暂时借花献佛了。 引用部分原文: Dr. Cliff Click在JavaOne 2003上发表的《Performance Myths Exposed》中,给出了一组其它条件都相同时,使用与不使用对象池化技术的实际性能的比较结果。他的实测结果表明: 对于类似Point这样的轻量级对象,进行池化处理后,性能反而下降,因此不宜池化; 对于类似Hashtable这样的中量级对象,进行池化处理后,性能基本不变,一般不必池化(池化会使代码变复杂,增大维护的难度); 对于类似JPanel这样的重量级对象,进行池化处理后,性能有所上升,可以考虑池化。 想看全部原文请到: http://www-900.ibm.com/developerWorks/cn/java/l-common-pool/index.shtml?ca=dwcn-newsletter-java |
26.Re:连接池是否有用? [Re: zane] | Copy to clipboard |
Posted by: faint Posted on: 2003-12-30 20:47 zane wrote: 我感觉你说的这个“连接池”非大家说的那个“连接池”虽然它们在英语里面都是“Connection Pooling”,上面大家说的“连接池”是基于Java Application的,即Pooling里面存储的是java.sql.Connection对象或者包装java.sql.Connection的对象(因实现的机制不同而不同),而你提到的Oracle中的"Connection Pooling"存储的应该Oracle自身缓冲机制的一种,其中缓冲的应该是和服务器端和Java Application相关非常紧密的一些东西。嗯,这句话可能说的非常不明白,举例说一下,看能不能说清楚。比如你创建一个PreparedStatement对象,这时候服务器端将会把PreparedStatement包装的SQL语句优化,并存储在缓冲里面,这个缓冲有自己特有的缓冲机制,且这种特有缓冲内容仅仅针对Java Application。 嗯,上面就是我的分析,简而言之应该有一下几点: 1.两者的基于的层次是不同的(application tier vs database server) 2.缓冲的内容不一样。(object vs something(已经编译SQL语句或者其它) 由于我对Oracle服务器端缓冲机制不是非常熟悉,上面的分析如果有错敬请指教。 |
27.Re:连接池是否有用? [Re: faint] | Copy to clipboard |
Posted by: zane Posted on: 2003-12-31 09:10 faint wrote: 这个server可以进行sql语句的优化嘛?这个要涉及到数据那边,做索引,还是全表扫描,你的sql语句是nested join,还是merg join,还是hash join 就比如走索引,是走哪个?它要根据对这个表的一个统计来做出决定, 我想服务器那段只是做一些会话方面的缓冲吧,还是要通过接口提交给 数据库来做这些。 |
28.Re:连接池是否有用? [Re: jackzhuo] | Copy to clipboard |
Posted by: net0309 Posted on: 2004-01-03 21:59 www.javaexchange.com |
29.Re:连接池是否有用? [Re: jackzhuo] | Copy to clipboard |
Posted by: findok Posted on: 2004-02-10 22:25 各位高手,请详细说说连接池的使用和建立,谢谢了! |
Powered by Jute Powerful Forum® Version Jute 1.5.6 Ent Copyright © 2002-2021 Cjsdn Team. All Righits Reserved. 闽ICP备05005120号-1 客服电话 18559299278 客服信箱 714923@qq.com 客服QQ 714923 |