| 网站首页 | 业界新闻 | 小组 | 威客 | 人才 | 下载频道 | 博客 | 代码贴 | 在线编程 | 编程论坛
欢迎加入我们,一同切磋技术
用户名:   
 
密 码:  
共有 943 人关注过本帖
标题:help me!!请问连接池是怎么一回事?
只看楼主 加入收藏
tianhe
Rank: 1
等 级:新手上路
帖 子:86
专家分:0
注 册:2005-3-17
收藏
 问题点数:0 回复次数:5 
help me!!请问连接池是怎么一回事?
连接池的问题我看了好长时间还是不懂,大家要多多指教哦.
搜索更多相关主题的帖子: help 
2005-10-05 15:36
zgy0209zgy
Rank: 1
等 级:新手上路
帖 子:71
专家分:0
注 册:2005-8-15
收藏
得分:0 
就是就是,大家说说
2005-10-05 23:44
唐伯猫
Rank: 8Rank: 8
等 级:贵宾
威 望:45
帖 子:5323
专家分:58
注 册:2005-8-9
收藏
得分:0 
              关于数据库连接池 在基于JDBC的数据库应用开发中,数据库连接的管理是一个难点,因为它是决定该应用性能的一个重要因素。 本文在对数据库连接进行透彻分析的基础上,提出并实现了一个高效的连接管理策略,使得开发高性能的数 据库应用变得相对容易。特别是,对于连接管理中的两个难点:事务和多线程问题进行了深入的剖析,并给 出了一个基于设计模式的解决方案。介绍在使用Java语言进行和数据库有关的的应用开发中,一般都使用 JDBC来进行和数据库的交互,其中有一个关键的概念就是Connection(连接),它在Java中是一个类, 代表了一个通道。通过它,使用数据的应用就可以从数据库访问数据了。对于一个简单的数据库应用, 由于对于数据库的访问不是很频繁。这时可以简单地在需要访问数据库时,就新创建一个连接,用完后就关闭它, 这样做也不会带来什么明显的性能上的开销。但是对于一个复杂的数据库应用,情况就完全不同了。频繁的建立、 关闭连接,会极大的减低系统的性能,因为对于连接的使用成了系统性能的瓶颈。本文给出的方法可以有效的解 决这个问题。在本方法中提出了一个合理、有效的连接管理策略,避免了对于连接的随意、无规则的使用。 该策略的核心思想是:连接复用。通过建立一个数据库连接池以及一套连接使用管理策略,使得一个数据库 连接可以得到高效、安全的复用,避免了数据库连接频繁建立、关闭的开销。另外,由于对JDBC中的原始连 接进行了封装,从而方便了数据库应用对于连接的使用(特别是对于事务处理),提高了开发效率,也正是 因为这个封装层的存在,隔离了应用的本身的处理逻辑和具体数据库访问逻辑,使应用本身的复用成为可能。 问题产生我参与的项目是开发一个网管系统,不可避免的要和数据库打交道。刚开始时,由于对于数据库的访 问不是很频繁,对于数据库连接的使用就是简单的需要时就建立,用完就关闭的策略, 这很符合XP(eXtreme Programming)的口号:"Do the Simplest Thing that Could Possibly Work"。 确实,开始时工作的很好。随着项目的进展,对于数据库的访问开始变的频繁,问题就暴露出来了,原先的通过 简单地获取和关闭数据库连接的方法将很大的影响系统的性能,这种影响是由于数据库资源管理器进程频繁的创 建和摧毁那些连接对象而引起的。此时,就有必要对数据库访问方法进行重构(refactoring),因为我们确实需要 进行改进,来提高系统的性能。解决方案可以看出,问题的根源就是由于对于连接资源的低效管理造成的。 对于共享资源,有一个很著名的设计模式:资源池。该模式正是为了解决资源频繁分配、释放所造成的问题的。 把该模式应用到数据库连接管理领域,就是建立一个数据库连接池,提供一套高效的连接分配、使用策略, 最终目标是实现连接的高效、安全的复用。 3.1、建立连接池第一步,就是要建立一个静态的连接池,所谓静态是指,池中的连接是在系统初始化时就分配好 的,并且不能够随意关闭的。Java中给我们提供很多容器类可以方便的用来构建连接池,如:Vector、Stack等。 在系统初始化时,根据配置创建连接并放置在连接池中,以后所使用的连接都是从该连接池中获取的,这样就可 以避免连接随意建立、关闭造成的开销(当然,我们没有办法避免Java的Garbage Collection带来的开销)。 3.2、分配、释放策略有了这个连接池,下面我们就可以提供一套自定义的分配、释放策略。当客户请求数据库连 接时,首先看连接池中是否有空闲连接,这里的空闲是指,目前没有分配出去的连接。如果存在空闲连接则把连 接分配给客户,并作相应处理,具体处理策略,在关键议题中会详述,主要的处理策略就是标记该连接为已分配。 若连接池中没有空闲连接,就在已经分配出去的连接中,寻找一个合适的连接给客户(选择策略会在关键议题中 详述),此时该连接在多个客户间复用。 当客户释放数据库连接时,可以根据该连接是否被复用,进行不同的处理。如果连接没有使用者,就放入到连 接池中,而不是被关闭。可以看出正是这套策略保证了数据库连接的有效复用。3.3、配置策略数据库连接池中 到底要放置多少个连接,连接耗尽后该如何处理呢?这时一个配置策略。一般的配置策略是,开始时,根据具 体的应用需求,给出一个初始的连接池中连接的数目以及一个连接池可以扩张到的最大连接数目。本方案就是 按照这种策略实现的。关键议题本节将对上述解决方案中的关键细节进行详述,正是这些关键的策略保证了数 据库连接复用的高效和安全。 4.1、引用记数3.2节中的分配、释放策略对于有效复用连接非常重要,我们采用的方法也是采用了一个很有名的 设计模式:Reference Counting(引用记数)。该模式在复用资源方面用的非常广泛 ,我们把该方法运用到对于连接的分配释放上。每一个数据库连接,保留一个引用记数,用来记录该连接的使用 者的个数。具体的实现上,我们采用了两极连接池,空闲池和使用池。空闲池中存放目前还没有分配出去被使用 的连接,一旦一个连接被分配出去,那么就会放入到使用池中,并且增加引用记数。这样做有一个很大的好处, 使得我们可以高效的使用连接,因为一旦空闲池中的连接被全部分配出去,我们就可以根据相应的策略从使用池 中挑选出一个已经正在使用的连接用来复用,而不是随意拿出一个连接去复用。策略可以根据需要去选择, 我们采用的策略比较简单:复用引用记数最小的连接。Java的面向对象特性,使得我们可以灵活的选择不同的策 略(提供一个不同策略共用的抽象接口,各个具体的策略都实现这个接口,这样对于策略的处理逻辑就和策略的 实现逻辑分离)。 4.2、事务处理前面谈到的都是关于使用数据库连接进行普通的数据库访问。对于事务处理,情况就变得比较复杂。 因为事务本身要求原子性的保证,此时就要求对于数据库的操作符合"All-All-Nothing"原则,即要么全部完成,要么 什么都不做。如果简单的采用上述的连接复用的策略,就会发生问题,因为没有办法控制属于同一个事务的多个 数据库操作方法的动作,可能这些数据库操作是在多个连接上进行的,并且这些连接可能被其他非事务方法复用。 Connection本身具有提供了对于事务的支持,可以通过设置Connection的AutoCommit属性为false,显式的调用commit 或者rollback方法来实现。但是要安全、高效的进行Connection进行复用,就必须提供相应的事务支持机制。我们 采用的方法是:采用显式的事务支撑方法,每一个事务独占一个连接。这种方法可以大大降低对于事务处理的复 杂性(如果事务不独占一条连接,那么要保证事务的原子性并且又不妨碍复用该连接的其他和该事务无关的操作, 基本上不可能,除非Connection类是你开发的),并且又不会妨碍连接的复用,因为隶属于该事务的所有数据库操 作都是通过这一个连接完成的,并且事务方法又复用了其他一些数据库方法。在我们的连接管理服务提供了显式 的事务开始、结束(commit或者rollback)声明,以及一个事务注册表,用于登记事务发起者和事务使用的连接的 对应关系,通过该表,使用事务的部分和我们的连接管理部分就隔离开,因为该表是在运行时根据实际的调用情 况,动态生成的。事务使用的连接在该事务运行中不能被复用。当使用者需要使用事务方法时,首先调用连接管 理服务提供的beginTrans方法, 该方法主要处理流程如下(伪码描述): public void beginTrans( ) { … conn = getIdleConnectionFromPoll( ); userId = getUserId( ); registerTrans(userId, conn); …} 在我们的实现中,用户标识是通过使用者所在的线程来标识的。后面的所有对于数据库的访问都是通过查找该注 册表,使用已经分配的连接来完成的。当事务结束时,从注册表中删除相应表项。对于嵌套的事务如何处理呢? 我们采用的方法仍为引用记数,不过这里的引用记数是指的"嵌套层次",具体的细节,不再赘述。 4.3、封装从上面的论述可以看出,普通的数据库方法和事务方法对于连接的使用(分配、释放)是不同的, 为了便于使用,对外提供一致的操作接口,我们对连接进行了封装:即普通连接和事务连接。在此,我们利用 了Java中的强大的面向对象特性:多态。普通连接和事务连接均实现了一个DbConnection接口,对于接口中定义 的方法,分别根据自己的特点作了不同的实现,这样在对于连接的处理上就非常的一致了。4.4、并发问题为了是 我们的连接管理服务有更大的通用性,就必须要考虑到多线程环境,即并发问题。在一个多线程的环境下,我们 必须要保证连接管理自身数据的一致性和连接内部数据是一致性,还好Java提供对这方面的很好的支持 (synchronized关键字),这样我们就很容易使连接管理成为线程安全的。5、结论本文给出了一个基本的连接管 理框架,在其中使用了一些广泛使用的设计模式(资源池,引用记数等),使得高效、安全的复用数据库连接成 为可能。当然,还有一些问题没有考虑到,比如:没有实现对不同种类的数据库的联合管理;没有提供定时检测 机制,查询连接的状态等。另外在连接管理的使用包装上比起一些商用的系统还显粗糙,但是底层的基理是一致 的,所以通过本文相信对于这些商用的产品中的相关功能会有更好的理解。 参考文献《Thinking in Java》Bruce Eckel《Real-Time Design Patterns》 Bruce Powel               数据库连接池简介 在传统的两层结构中,客户端程序在启动时打开数据库连接,在退出程序时关闭数据库连接。这样,在整个程序运行中,每个客户端始终占用一个数据库连接,即使在大量没有数据库操作的空闲时间,如用户输入数据时,从而造成数据库连接的使用效率低下。 在三层结构模式中,数据库连接通过中间层的连接池管理。只有当用户真正需要进行数据库操作时,中间层才从连接池申请一个连接,数据库操作完毕,连接立即释放到连接池中,以供其他用户使用。这样,不仅大大提高了数据库连接的使用效率,使得大量用户可以共享较少的数据库连接,而且省去了建立连接的时间。 连接池的配置使用 数据库连接池是应用服务器的一项基本功能,我们以Apusic Application Server为例,来说明JDBC连接池的配置使用。 Apusic JDBC连接池提供对多种数据库的支持,如Oracle、MS SqlServer、Sybase、Informix、DB2等。 Apusic JDBC连接池可以通过数据库本身的JDBC Driver连接到数据库,也可以通过JDBC-ODBC桥连接到数据库。下面我们以Oracle为例说明如何配置连接池: Oracle数据库的JDBC Driver包文件classes111.zip在/usr/oracle/jdbc/lib(假设oracle的安装目录是/usr/oracle)目录下,首先将classes111.zip加入到系统的CLASSPATH中。然后在apusic/config/apusic.conf(假设安装目录为apusic) 中作如下设置: <SERVICE CLASS="com.apusic.jdbc.PoolManager" NAME="JdbcPool:name=jdbc/sample" > <ATTRIBUTE NAME="ExpirationTime" VALUE="300"/> <ATTRIBUTE NAME="MinCapacity" VALUE="5"/> <ATTRIBUTE NAME="URL" VALUE="jdbc:oracle:thin:@192.168.19.136:1521:orcl"/> <ATTRIBUTE NAME="ConnectionProperties" VALUE="user=gtj,password=abc123"/> <ATTRIBUTE NAME="DriverClassName" VALUE="oracle.jdbc.driver.OracleDriver" /> <ATTRIBUTE NAME="MaxCapacity" VALUE="30"/> </SERVICE> ExpirationTime: 超时时间,单位是秒。当一个数据库连接超过expirationTime设定时间不被使用 时,系统会自动关闭这个数据库连接。默认值为300秒 MinCapacity: 最小连接数 URL: 数据库的URL ConnectionProperties: 连接属性,其中:user用户名,password密码 DriverClassName: JDBC驱动程序类名 MaxCapacity: 最大连接数 192.168.19.136: oracle所在计算机的IP地址。 调用连接池 我们以一个JSP程序为例,说明如何使用连接池。首先通过JNDI得到DataSource,再的得到连接Connection,如下例所示: <html> <head> <title>Jsp sample</title> </head> <body> <p> <%@ page contentType="text/html;charset=gb2312" %> <%@ page import=" java.sql.*, javax.naming.*, javax.sql.* "%> <% try{ Context ctx = new InitialContext(); DataSource ds = (DataSource)ctx.lookup("jdbc/sample"); Connection con = ds.getConnection(); Statement stmt = con.createStatement(); ResultSet rs = stmt.executeQuery("select ENAME from EMP"); while(rs.next()){ out.println("<p>" + rs.getString(1)); } rs.close(); stmt.close(); }catch(Exception e){ System.out.println("jsp:" + e.getMessage()); }finally{ try{ con.close(); }catch(Exception e1){} } %> </body> </html>
<SCRIPT type=text/javascript>
		
2005-10-09 20:03
bceric
Rank: 1
等 级:新手上路
帖 子:25
专家分:0
注 册:2005-9-14
收藏
得分:0 
原理明白了, 怎么用还是不懂呦!!!

2005-10-10 14:59
快速回复:help me!!请问连接池是怎么一回事?
数据加载中...
 
   



关于我们 | 广告合作 | 编程中国 | 清除Cookies | TOP | 手机版

编程中国 版权所有,并保留所有权利。
Powered by Discuz, Processed in 0.082537 second(s), 9 queries.
Copyright©2004-2024, BCCN.NET, All Rights Reserved