在做一個注冊頁面的時候,要用到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 要作為成員變量,只執行一次,創建連接池,以后用戶只需取用即可