在做一个注册页面的时候,要用到ajax异步校验用户输入的信息是否正确,还得做用户名查重工作,所以需要频繁的访问数据库。我用的c3p0的一个操作数据库的utils是我自己在我看完学习视频之后做的,我做的utils和视频中做的不同的是:视频中做的utils是注册驱动、设置ComboPooledDataSource和获得connection分开,我做的是一个getConnection方法一步到位。平常使用数据库频率不高也就没发现什么问题,直到现在东窗事发......
昨天出现了错误Too many connections ;我还纳闷我每次用完连接都会关闭,为什么会Too many connections ...
使用命令 show full processlist; 发现居然有上2万个sleep连接,
一停止程序运行又只剩下一个链接(就是本机连接),
检查了一下代码,发现“创建连接池”和“取用连接”和“关闭连接”代码放在一起,导致了这样一个工作流程:
一个用户访问----->创建一个链接池(20个连接)--->取用一个连接----->关闭一个链接;
于是多次访问(多个用户访问)的时候就创建了多个连接池,但每一个用户都只关闭了其中一个链接,留下一堆链接;
比如,30个用户访问,每个用户访问都创建一个20个连接的连接池,总共创建了600个链接,但30个用户全部访问结束时,总共才关闭了30个链接,留下570个链接。
用户越来越多,导致无用的链接越来越多,所以就有了Too many connections
正确的使用数据库做法是:先设置ComboPooledDataSource;再调用一个链接,而且每次调用都要关闭;
参考以下程序(测试程序,不是注册程序)
public class C3p0 { ComboPooledDataSource dataSource = new ComboPooledDataSource(); @Test public void name() throws Exception {//1000次测试 setConnection(); for(int i=0;i<1000;i++){ Thread.sleep(200); operateDatabase(); System.out.println(i); } } /** * 演示c3p0的使用方法 * @project_name Day11 * @class_name C3P0Demo * @author Dovinya * @data 2014-8-27 下午07:57:42 * @version 1 * @notes */ public void setConnection() {//设置ComboPooledDataSource try { dataSource.setDriverClass("com.mysql.jdbc.Driver"); dataSource.setJdbcUrl("jdbc:mysql://localhost:3306/kxpro"); dataSource.setUser("root"); dataSource.setPassword("514079"); dataSource.setMinPoolSize(5);//连接池最小连接数 dataSource.setInitialPoolSize(20);//连接池创建时连接数 dataSource.setMaxPoolSize(80);//连接池最大连接数 dataSource.setAcquireIncrement(5);//链接用完时创建的连接数 dataSource.setNumHelperThreads(5);//多线程执行,提升性能 } catch (Exception e) { // TODO Auto-generated catch block e.printStackTrace(); System.out.println("没找到驱动"); } } @Test public void operateDatabase() { //使用链接 Connection conn =null; PreparedStatement ps = null; ResultSet rs = null; try { // Class.forName("com.mysql.jdbc.Driver"); // conn = DriverManager.getConnection("jdbc:mysql://localhost:3306/day11", "root", "123"); // ps = conn.prepareStatement("select * from account"); conn = dataSource.getConnection(); ps = conn.prepareStatement("select * from login"); rs = ps.executeQuery(); while(rs.next()){ System.out.println(rs.getString("username")); } while(rs.next()){ String name = rs.getString("name"); System.out.println(name); } } catch (Exception e) { e.printStackTrace(); }finally{ if(rs!=null){ try { rs.close(); } catch (SQLException e) { e.printStackTrace(); }finally{ rs=null; } } if(ps!=null){ try { ps.close(); } catch (SQLException e) { e.printStackTrace(); }finally{ ps=null; } } if(conn!=null){ try { conn.close(); System.out.println("conn yiguanbi"); } catch (SQLException e) { e.printStackTrace(); }finally{ conn=null; } } } } }
最重要的是ComboPooledDataSource 要作为成员变量,只执行一次,创建连接池,以后用户只需取用即可