本连接池的建立使用输入流,通过上下文环境,读取配置文件(Dbconfig.Prooperties)里预先设置的参数,部分代码如下: 内容来自论文无忧网 www.paper51.com
public voidcontextInitialized(ServletContextEvent event) 内容来自www.paper51.com
{ copyright paper51.com Properties ps = new Properties(); http://www.paper51.com
Vector connections = new Vector(); copyright paper51.com ServletContext context = event.getServletContext(); http://www.paper51.com try copyright paper51.com
{ copyright paper51.com
//使用输入流,读取配置文件里的各种参数 内容来自www.paper51.com InputStreaminput = getClass().getResourceAsStream("/DBconfig.properties"); paper51.com
ps.load(input); paper51.com input.close(); paper51.com url = (String) ps.get("url"); copyright paper51.com user = (String) ps.get("user"); paper51.com passWord = (String) ps.get("passWord"); copyright paper51.com DriverName = (String) ps.get("DriverName"); 内容来自www.paper51.com maxConnections=Integer.parseInt(((String)ps.get("maxConnections")).trim(), 10); http://www.paper51.com System.out.println(user); paper51.com //循环加入取得的连接到Vector中 paper51.com for (int i = 0; i < maxConnections; i++) http://www.paper51.com { copyright paper51.com //调用下面的方法,取得数据库连接,并放入到Vector中 paper51.com connections.add(getConnection(url,user,passWord,DriverName)); 内容来自论文无忧网 www.paper51.com
} paper51.com } http://www.paper51.com catch (Exception e) http://www.paper51.com { http://www.paper51.com e.printStackTrace(); 内容来自www.paper51.com
} 内容来自论文无忧网 www.paper51.com //放到服务器的上下文环境中 内容来自论文无忧网 www.paper51.com
context.setAttribute("CONNECTOR",new DBConnectionPool(connections)); http://www.paper51.com } 内容来自www.paper51.com 连接池初始化参数通过页面设置写入DBconfig.properties文件中,如下图所示: copyright paper51.com
copyright paper51.com 图5 初始化连接池设置 内容来自论文无忧网 www.paper51.com 4.2 连接池的管理 paper51.com 连接池管理策略是连接池机制的核心。当连接池建立后,如何对连接池中的连接进行管理,解决好连接池内连接的分配和释放,对系统的性能有很大的影响。连接的合理分配、释放可提高连接的复用,降低了系统建立新连接的开销,同时也加速了用户的访问速度。下面介绍连接池中连接的分配、释放策略。 paper51.com 连接池的分配、释放策略对于有效复用连接非常重要。就一般情况而言,当客户释放数据库连接时,先判断该连接的引用次数是否超过了规定值,如果超过就删除该连接,并判断当前连接池内总的连接数是否小于minConn(最小连接数),若小于就将连接池充满;如果没超过就将该连接标记为开放状态,可供再次复用。可以看出正是这套策略保证了数据库连接的有效复用,避免频繁地建立、释放连接所带来的系统资源开销。我们采用的方法是一个很有名的设计模式:Reference Counting(引用记数)。该模式在复用资源方面应用的非常广泛,把该方法运用到对于连接的分配释放上,为每一个数据库连接,保留一个引用记数,用来记录该连接的使用者的个数。具体的实现方法是: http://www.paper51.com publicsynchronized Connection getConnection(int TimeOut) 内容来自论文无忧网 www.paper51.com { 内容来自www.paper51.com
Connection con = null; copyright paper51.com
if(freeConnections.size() <= 0) http://www.paper51.com { copyright paper51.com System.out.println("连接失败,由于数据库连接池中无可用连接!请等待!"); paper51.com try { 内容来自www.paper51.com newDBConnectionManager().closeAll(); copyright paper51.com
} 内容来自论文无忧网 www.paper51.com catch (Exception ex) paper51.com { 内容来自www.paper51.com ex.printStackTrace(); paper51.com } copyright paper51.com return con; paper51.com } http://www.paper51.com else copyright paper51.com
{ http://www.paper51.com Connection temp = (Connection) freeConnections.firstElement(); http://www.paper51.com
freeConnections.remove(temp); http://www.paper51.com nowConnections.add(temp); 内容来自www.paper51.com return temp; 内容来自www.paper51.com
} copyright paper51.com } http://www.paper51.com 当应用程序向数据库发起连接请求时,会检查连接池中是否存在空闲的连接。如果存在空闲的连接,连接池则把空闲连接分配给客户,并将该连接做相应处理,即标记为正在使用的连接,并将引用计数加1。如果不存在空闲连接,则检查连接池里的连接数是否已经达到了最大连接数(maxConn),若没有达到就为应用程序创建一个新的连接;若达到了最大连接数,那么就需要等待连接的释放,等待连接的释放时间是由系统中预先定义好的一个超时参数(Timeout)来做判断。如果在超时等待(TimeOut)后仍没有可用的空间连接,程序上便会返回一个null值,同时抛出无空闲连接的异常给用户。 paper51.com
publicvoid TimeOut(int TimeOut, Connection con) paper51.com { http://www.paper51.com
try { http://www.paper51.com Thread t = new Thread(); http://www.paper51.com t.start(); copyright paper51.com
t.run(); 内容来自论文无忧网 www.paper51.com t.wait(TimeOut); http://www.paper51.com closeConnection(con); paper51.com t.destroy(); copyright paper51.com } copyright paper51.com catch (Exception ex) paper51.com
{ 内容来自论文无忧网 www.paper51.com ex.printStackTrace(); copyright paper51.com } 内容来自www.paper51.com } 内容来自www.paper51.com
已用连接计数器的问题交由JSP页面中的循环来处理,每当应用程序申请一个连接时,计数器便会循环一次,部分实现代码如下: 内容来自论文无忧网 www.paper51.com for(int i = 0; i < cp.getNowConnections().size(); i++) 内容来自论文无忧网 www.paper51.com
{ paper51.com out.println("<font color=blue>连接名称" + (i+ 1) + ":</font>" +cp.getNowConnections().get(i) + "<br>"); copyright paper51.com con = (Connection)cp.getNowConnections().get(0); 内容来自www.paper51.com
} copyright paper51.com
对于未用连接的处理与已用连接类似,部分实现代码如下: paper51.com for(int j = 0; j < cp.getFreeConnections().size(); j++) 内容来自www.paper51.com { 内容来自论文无忧网 www.paper51.com out.println("<font color=blue>未用连接名称" +(j + 1) + ":</font>" +cp.getFreeConnections().get(j) + "<br>"); 内容来自www.paper51.com } 内容来自www.paper51.com 连接池的调用如下图所示,若连接已分配完毕,系统提示等待连接释放。 paper51.com copyright paper51.com 图6 连接的调用 paper51.com
4.3 连接池的关闭 copyright paper51.com 当应用程序退出时,通过调用closeAll()方法来关闭连接池中的连接,此时应把在连接池建立时向数据库申请的连接对象统一归还给数据库(即关闭所有数据库连接)。 copyright paper51.com publicvoid closeAll() http://www.paper51.com { paper51.com try paper51.com { 内容来自www.paper51.com if (rs != null) rs.close(); 内容来自www.paper51.com
if (smt != null) smt.close(); http://www.paper51.com
if (psmt != null) psmt.close(); 内容来自www.paper51.com if (con != null) provider.closeConnection(con); 内容来自www.paper51.com } paper51.com
catch (Exception e) http://www.paper51.com { 内容来自www.paper51.com e.printStackTrace(); http://www.paper51.com } 内容来自www.paper51.com } copyright paper51.com 4.4 连接池的测试 内容来自www.paper51.com 对于一个好的连接池,性能显得尤为重要。性能不仅仅体现的是对数据库操作的处理速度还有连接池自身的稳定性。通过压力测试,对比能够看出DBCP连接池要比Hibernate3.0默认自带的数据库连接池c3p0快,但是稳定性却不如它,并发用户过多常常会自动断开连接。通过对本连接池的测试发现,有连接池的时候对数据库的操作要比没有连接池的时候快3-5秒。 copyright paper51.com 一般数据库连接池采用DBCP作为连接池时,默认的初始化为50个,速度不会有太大问题。正常情况下,系统没问题,压力测试从10个并发开始,每一次增量是增加10个并发,至200-400并发用户将成为一个重要节点,性能的优越能得以体现。而本连接池没有经过压力测试,多用户的并发访问时其稳定性还有待验证。 copyright paper51.com 5 系统测试问题总结 http://www.paper51.com 5.1 连接池的泄露问题5.1.1 产生现象 http://www.paper51.com 当系统访问量较大时,会出现连接池连接数居高不下的情况,如果在关闭数据库连接的过程中发生错误会导致他们不再会被重用。这就叫做“数据库连接池泄漏”。这将会最终导致web应用程序数据库连接失败。甚至造成连接池崩溃,从而无法进行数据交互,服务器当机。 http://www.paper51.com 5.1.2 解决办法 内容来自www.paper51.com
常见的程序错误写法有以下两种: 内容来自www.paper51.com
1、当连接执行数据库操作出错时,未执行数据库关闭。 paper51.com
Connectionconn = DbUtil.getConnection(); 内容来自www.paper51.com …….//执行数据库操作 内容来自论文无忧网 www.paper51.com DbUtil.closeConnection(); http://www.paper51.com 在以上代码中,如果执行数据库操作过程中,出现异常,系统从出现异常处停止,不再执行下面的代码,造成数据库连接池无法回收,连接泄露的情况。正确的代码写法应如下: copyright paper51.com Try{ copyright paper51.com Connectionconn = DbUtil.getConnection(); paper51.com …….//执行数据库操作 copyright paper51.com } http://www.paper51.com catch(Exceptione) paper51.com
{ 内容来自www.paper51.com } http://www.paper51.com finally{ 内容来自论文无忧网 www.paper51.com DbUtil.closeConnection(); //异常处理后必须处理的方法。 copyright paper51.com } paper51.com 这样将保证了在执行数据库操作过程中即使出现异常,也将能够执行数据库连接池的回收。 copyright paper51.com |