歲月如哥
          人生非夢(mèng)
          posts - 50,comments - 144,trackbacks - 0
          XX系統(tǒng)在生產(chǎn)環(huán)境使用一定時(shí)間后表現(xiàn)出用戶不能登錄,后臺(tái)tomcat日志報(bào)如下錯(cuò):
             
           2008-08-14 12:31:35,029 [org.hibernate.util.JDBCExceptionReporter]-[WARN] SQL Error: 0, SQLState: null
             
          2008-08-14 12:31:35,029 [org.hibernate.util.JDBCExceptionReporter]-[ERROR] Cannot get a connection, pool exhausted
             
          2008-08-14 12:31:35,029 [org.hibernate.util.JDBCExceptionReporter]-[WARN] SQL Error: 0, SQLState: null
             
          2008-08-14 12:31:35,029 [org.hibernate.util.JDBCExceptionReporter]-[ERROR] Cannot get a connection, pool exhausted

             顯然是連接池滿了,駐地工程師重啟之后就可以正常使用了。因?yàn)槲覀兊膖omcat連接池的配置連接參數(shù)好像很大,所以應(yīng)該肯定是程序出問題了。后來在測(cè)試那也出現(xiàn)了同樣的問題,因?yàn)闇y(cè)試的人比較多,所以那兩天基本上一兩個(gè)小時(shí)連接池就滿了,當(dāng)時(shí)只能一次一次的重啟tomcat。
             因?yàn)閄X系統(tǒng)之前已經(jīng)修改過一次因?yàn)?span id="wmqeeuq" class="t_tag" onclick="tagshow(event)" href="tag.php?name=%B4%FA%C2%EB">代碼的錯(cuò)誤而導(dǎo)致的數(shù)據(jù)連接沒有釋放的問題,所以這一次的問題比較不好定位,不能知道是哪些操作的連接池沒有釋放。
             后來由zhxy提供了如下的查看當(dāng)前數(shù)據(jù)庫(sybase)哪些連接沒有被釋放的腳本,其中的ip為tomcat的發(fā)布地址(因?yàn)閿?shù)據(jù)庫連接都是由tomcat發(fā)起):
          declare cur_spid cursor 
          for
          select spid from sysprocesses where ipaddr='172.16.7.8'
          go

          declare @spid Integer
          open  cur_spid
          fetch cur_spid into @spid 
          while @@sqlstatus=0
          begin
                  
          print '%1!' , @spid
            
          dbcc traceon(3604)
            
          dbcc sqltext(@spid )
            
          fetch cur_spid into @spid 
          end
          close cur_spid

          使用該腳本只能之后,執(zhí)行結(jié)果都是打印出大量類似的下面的三行:
          184
          DBCC execution completed. If DBCC printed error messages, contact a user with System Administrator (SA) role. 
          SQL 
          Textset CHAINED off 
          直接使用上面的腳本打印的結(jié)果是當(dāng)前占用數(shù)據(jù)庫連接池的spid(第一行),以及連接正在執(zhí)行的sql(第三行)。   
            后來發(fā)現(xiàn)每登錄一次審判系統(tǒng),使用上面的腳本執(zhí)行結(jié)果就會(huì)有一個(gè)連接沒有被釋放(一般連接會(huì)在一段時(shí)間之后釋放),除非是重啟tomcat否則一直占用。
            跟蹤登陸代碼發(fā)現(xiàn)有如下的寫法(調(diào)用存儲(chǔ)過程):
          Session session = this.getSession();
                  Transaction tx 
          = session.beginTransaction();
                  Connection con 
          = session.connection();
                  
          try {          
                            
          //……  
                      CallableStatement cstmt = con.prepareCall("{call K_TJ..PR_GET_AjCount(?,?,?,?,?,?,?,?,?,?,?,?) }");
                      
          //…… 
                      ResultSet resultSet = cstmt.executeQuery();
                      tx.commit();
                      
          if (resultSet.next())
                          ajCount 
          = resultSet.getInt(1);
                      resultSet.close();
                  } 
          catch (Exception e) {
                          tx.rollback();
                      e.printStackTrace();
                      
          return 0;
                  } 
          finally{
                          
          try
                      {
                          con.close();
                      }
                      
          catch (SQLException e)
                      {
                          e.printStackTrace();
                      }
                  }

          這里有幾個(gè)問題,一是把hibernate和connection的用法使用混亂了;二是使用session獲取的連接不需要自己關(guān)閉,應(yīng)該關(guān)閉session(一個(gè)session對(duì)應(yīng)一個(gè)connection),這里剛好用使用反了。
                后來試著把con.close()改成session.close()問題就沒有了,后來經(jīng)zhangjy提醒,如果是使用spring提供的getSession()獲取的連接,最好是使用releaseSession()方法進(jìn)行釋放。引用原話“release不一定是關(guān)閉連接,就像連接池的連接一樣。release只是放回池中,你要關(guān)閉了 就不能放回池中了 而且 直接close可能會(huì)拋異常,release不會(huì)拋異常 因?yàn)槔镞呌袑?duì)環(huán)境的判斷”,把con.close()改成releaseSession()問題也解決了。
                但是我們的項(xiàng)目中使用了spring,對(duì)存儲(chǔ)過程調(diào)用最好是使用jdbcTemplate。退一步如果要獲取一個(gè)connection,最好能使用Summer提供的jdbcDao獲取,即jdbcdao.getDataSource().getConnection(),當(dāng)然這樣的連接完全就需要自己手工關(guān)閉了。
                最后搜了一下代碼,把程序中如上調(diào)用存儲(chǔ)過程的地方全部改為使用jdbcTemplate問題解決。最終代碼如下:
          getJdbcDAO().getJdbcTemplate().execute(
                          
          "{call K_TJ..PR_GET_AjCount(?,?,?,?,?,?,?,?,?,?,?,?) }",
                          
          new CallableStatementCallback() {
                            
          public Object doInCallableStatement(CallableStatement cstmt)
                                          
          throws SQLException, DataAccessException {
                                  
          //……
                                  ResultSet resultSet = cstmt.executeQuery();
                                  
          if (resultSet.next())
                                    
          return new Integer(resultSet.getInt(1));
                                  
          // ……
                          });
          連接池的問題解決。
          posted on 2008-08-30 15:03 歲月如歌 閱讀(7193) 評(píng)論(2)  編輯  收藏 所屬分類: java

          FeedBack:
          # re: 數(shù)據(jù)庫連接池滿的問題
          2008-12-17 10:21 | husl
          謝謝,寫得不錯(cuò),借用了,^_^  回復(fù)  更多評(píng)論
            
          # re: 數(shù)據(jù)庫連接池滿的問題[未登錄]
          2012-09-18 09:29 | c
          頂一下  回復(fù)  更多評(píng)論
            
          主站蜘蛛池模板: 沅陵县| 东乡县| 铁岭市| 泾源县| 澄江县| 龙山县| 班玛县| 凤冈县| 寻甸| 抚州市| 卫辉市| 航空| 正蓝旗| 茶陵县| 太康县| 开远市| 措美县| 成都市| 康定县| 瓮安县| 南乐县| 古蔺县| 上蔡县| 洞头县| 兰坪| 贵港市| 炎陵县| 行唐县| 离岛区| 深圳市| 元氏县| 内黄县| 怀来县| 景德镇市| 兴和县| 德清县| 商丘市| 余庆县| 德格县| 怀安县| 教育|