c3p0数据库连接池如何正确的关闭资源(“too many connections”的解决办法)

一.问题分析

关于c3p0数据库连接池的资源的关闭是一个很重要的问题,但是资源的关闭不仅仅是只调用close()方法,将链接放入池中那么简单,如果你不考虑数据源DataSource的关闭,那么你的Demo将在很少的数据库交互之后报出“too many connections”。下面先看这样一些代码(注:测试程序我也就不按照正确的开发模式写代码了):

CreateConnection.java(本文讨论的重点在这里)

public class CreateConnection {
    private ComboPooledDataSource dataSource=new ComboPooledDataSource("mysql");
    public Connection getConnection(){
        Connection conn=null;
        try {
            conn=dataSource.getConnection();
        } catch (SQLException e) {
            e.printStackTrace();
        }
        return conn;
    }

    public DataSource getDataSource() {
        return dataSource;
    }
    public void closeConn(Connection conn){
        try {
            if(conn!=null && conn.isClosed()){
                conn.close();
            }
        } catch (SQLException e) {
            e.printStackTrace();
        }
    }
}

testDao.java

public class testDao {
    public int reginster (String username,String pwd){
        CreateConnection c=new CreateConnection();
        Connection conn=c.getConnection();
        int i=0;
        String sql="insert into user(username,pwd)values(?,?)";
        try {
            PreparedStatement ps = conn.prepareStatement(sql);
            ps.setString(1,username);
            ps.setString(2,pwd);
            i=ps.executeUpdate();
        }catch (Exception ex){
            ex.printStackTrace();
        }finally{
            try {
                c.closeConn(conn);
            }catch (Exception ex){
                ex.printStackTrace();}
        }
        return i;
    }
}

testServlet.java

public class testServlet extends HttpServlet {
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
         String username=request.getParameter("username");
         String pwd=request.getParameter("pwd");
         testDao td=new testDao();
         response.setCharacterEncoding("utf-8");
         response.setContentType("text/html;charset=utf-8");
        int i=td.reginster(username,pwd);
        if(i==1){
            System.out.println("------------------------test");
            response.getWriter().print("<script language='javascript'>alert('注册成功!!!');history.back(-1)</script>");
        }else{
            response.getWriter().print("<script language='javascript'>alert('注册失败!!!');history.back(-1)</script>");
        }
    }

    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
           doPost(request,response);
    }
}

login.jsp

<%@ page language="java" import="java.util.*" contentType="text/html; charset=utf-8"%>
<html>
<head>
    <title>注册</title>
</head>
<body>
<form action="bluemsun/testServlet" method="post">
   用户名: <input type="text" name="username"/><br>

    密码:<input type="password" name="pwd"/>
    <input type="submit" value="注册"/>
</form>
</body>
</html>

上边程序在进行多次交互之后会报出“too many connections”的错误,原因分析如下:原因就在于程序只将链接放回了链接池使其处于空闲状态,但是却没有关闭dataSource,这就导致目前dataSource中的初始化链接一直处于链接池中,当下一次交互开始后又重新创建了新的dataSource,而下一次的dataSource还是不能被关闭,就这样每次都会累积不能被重用的链接,假如在配置时连接池的初始链接至配置数时100,而数据库的最大链接数是1000,那么在经过10次交互后会出现“too many connections”的错误。然而当把资源关闭的方法修改成如下的方法时就会发现永远不会报出”too many connections”的错误:

public void closeConn(Connection conn){
        try {
            if(conn!=null && conn.isClosed()){
                conn.close();
            }
          datasource.close();
         } catch (SQLException e) {
            e.printStackTrace();
         }
    } datasource.close();
         } catch (SQLException e) {
            e.printStackTrace();
         }
    }

上边贴出来的方法时将DataSource也进行了关闭。

二.方法改进

通过上边的分析,我们基本知道了问题出现的原因了,接下来就是改进连接池的使用了,先贴一下改进的代码:

public class C3P0Util {
	 private static DataSource dataSource=null;  
	    static{  
	        dataSource=new ComboPooledDataSource("mysql1");  
	    }  
	      
	    /** 
	     * 获取数据库连接 
	     * @return 
	     */  
	    public static Connection getConnection(){  
	        Connection conn=null;  
	        try {  
	             conn=dataSource.getConnection();  
	        } catch (SQLException e) {  
	            e.printStackTrace();  
	        }  
	        return conn;  
	    }  
	  
	    public static DataSource getDataSource() {
	        return dataSource;
	    }
	    /** 
	     * 
	     * @param conn 
	     */  
	    public static void closeConn(Connection conn){  
	        try {  
	            if(conn!=null && conn.isClosed()){  
	                conn.close();  
	            }  
	        } catch (SQLException e) {  
	            e.printStackTrace();  
	        }  
	    }  
}

从上边程序中我们可以看出,是把所有的资源都用static描述,也就是把所有资源都交给了类,这样做的好处是,每次交互都是共享C3P0Util类的datasource资源,不需要每次创建和关闭datasource资源,真正体现出了链接池的‘池’的特性。

  • 8
    点赞
  • 19
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 12
    评论
评论 12
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

浪舟子

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值