iamhuzl

            BlogJava :: 首頁 :: 新隨筆 :: 聯(lián)系 :: 聚合  :: 管理 ::
            1 隨筆 :: 13 文章 :: 21 評論 :: 0 Trackbacks
            忙碌的工作讓我很久沒有寫過博客了,另外技術上也沒有明顯的進步,也缺乏興奮點。項目正式上線很長時間,隨要訪問壓力的增大,每天PV差不多有500萬。這時出現(xiàn)了一些問題,主要的是訪問響應慢,程序中未發(fā)現(xiàn)異常。錯誤日志有數(shù)據(jù)庫連接的錯誤,懷疑是數(shù)據(jù)庫連接丟失或有某些請求會鎖表。因此寫一段代碼跟蹤數(shù)據(jù)庫連接獲取和釋放的情況。
             原理很簡單,攔截DataSource的getConnnection方法,把當前Connection和調用堆棧保存到連接列表;攔截Connection對象close方法,把Connection從連接列表中刪除。
            直接上代碼:
           
          package com.emagsoftware;
          
          import java.lang.reflect.Method;
          import java.sql.Connection;
          import javax.sql.DataSource;
          
          import net.sf.cglib.proxy.Enhancer;
          import net.sf.cglib.proxy.MethodInterceptor;
          import net.sf.cglib.proxy.MethodProxy;
          import org.springframework.beans.factory.FactoryBean;
          import org.springframework.beans.factory.config.BeanPostProcessor;
          
          import org.apache.log4j.Logger;
          
          import java.util.Map;
          import java.util.concurrent.ConcurrentHashMap;
          
          /**
           * DataSource connection監(jiān)控處理
           *
           * @author huzl
           * @date 2010-11-26 9:42:17
           */
          class DataSourceBeanPostProcessor implements BeanPostProcessor {
              public static Map connections = new ConcurrentHashMap();
              public static Map connectionTime = new ConcurrentHashMap();
              Logger log = Logger.getLogger(DataSourceBeanPostProcessor.class);
          
              public Object postProcessBeforeInitialization(Object object, String name) {
                  return object;
              }
          
              //創(chuàng)建DataSource或DataSource工廠的代理
              public Object postProcessAfterInitialization(Object object, String name) throws org.springframework.beans.BeansException {
                  if (!"dataSource".equals(name)) return object;
                  System.out.println("****************DataSource postProcessAfterInitialization success ");
                  if (object instanceof FactoryBean)
                      return createDataSourceFactoryProxy((FactoryBean) object);
                  else
                      return createDataSourceProxy((DataSource) object);
          
              }
              
              private FactoryBean createDataSourceFactoryProxy(final FactoryBean factoryBean) {
                  if (Enhancer.isEnhanced(factoryBean.getClass())) return factoryBean;
                  MethodInterceptor factoryInterceptor = new MethodInterceptor() {
                      public java.lang.Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws java.lang.Throwable {
                          Object result = method.invoke(factoryBean, args);
                          if ("getObject" != method.getName()) return result;
                          return createDataSourceProxy((DataSource) result);
                      }
                  };
                  return (FactoryBean) createProxy(FactoryBean.class, factoryInterceptor);
              }
              //攔截DataSource getConnection方法,記錄獲取的數(shù)據(jù)庫連接
              private DataSource createDataSourceProxy(final DataSource dataSource) {
                  if (Enhancer.isEnhanced(dataSource.getClass())) return dataSource;
                  MethodInterceptor dataSourceInterceptor = new MethodInterceptor() {
                      public java.lang.Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws java.lang.Throwable {
                          Object result = method.invoke(dataSource, args);
                          if ("getConnection" != method.getName()) return result;
                          connections.put(result, new Exception());
                          connectionTime.put(result, new java.util.Date());
                          System.out.println("****************DataSource Connection  get  size = " + connections.size());
                          return createConnectionProxy((Connection) result);
                      }
                  };
                  return (DataSource) createProxy(DataSource.class, dataSourceInterceptor);
              }
              //攔截Connection close方法,清除釋放的數(shù)據(jù)庫連接
              private Connection createConnectionProxy(final Connection conn) {
                  if (Enhancer.isEnhanced(conn.getClass())) return conn;
                  MethodInterceptor connectionProxy = new MethodInterceptor() {
                      public java.lang.Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws java.lang.Throwable {
                          if ("close" == method.getName()) {
                              connections.remove(conn);
                              connectionTime.remove(conn);
                              System.out.println("****************DataSource Connection close size = " + connections.size());
                          }
                          return method.invoke(conn, args);
                      }
                  };
                  return (Connection) createProxy(Connection.class, connectionProxy);
              }
          
              private Object createProxy(Class targetInterfaceClass, MethodInterceptor interceptor) {
                  Enhancer enhancer = new Enhancer();
                  enhancer.setInterfaces(new Class[]{targetInterfaceClass});
                  enhancer.setCallback(interceptor);
                  return enhancer.create();
              }
          
          }
          
          
            

            spring配置文件
           
          <bean class="com.emagsoftware.DataSourceBeanPostProcessor"/>
            

          寫一個頁面,檢查connections和connectionTime中的對象即可
          <%@ page import="org.apache.commons.lang.exception.ExceptionUtils" %>
          <%@ page import="java.util.Iterator" %>
          <%@ page import="com.emagsoftware.DataSourceBeanPostProcessor" %>
          <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
          <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="zh-CN" dir="ltr">
          
          <head>
              <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
              <title>連接池查詢</title>
              <style type="text/css">
                  .hidden{
                      display: none;
                  }
              </style>
          
          </head>
          <body>
              <h1>連接池(<%=DataSourceBeanPostProcessor.connections.size()%>)</h1>
              <%
                  if(DataSourceBeanPostProcessor.connections.size()>0){
                      out.println("時間:" + DataSourceBeanPostProcessor.connectionTime.values() + "
          ");
                      Iterator iterator = DataSourceBeanPostProcessor.connections.values().iterator();
                      while(iterator.hasNext())
                      {
                          Exception ex = (Exception) iterator.next();
                          out.println("<pre>" + ExceptionUtils.getFullStackTrace(ex) + "</pre>
          ");
                      }
                  }
              %>
          </body>
          </html>
          
          


          已有 0 人發(fā)表留言,猛擊->>這里<<-參與討論


          ITeye推薦



          posted on 2011-12-03 00:36 溫水青蛙 閱讀(1320) 評論(3)  編輯  收藏

          評論

          # re: jdbc數(shù)據(jù)庫連接丟失或未釋放情況跟蹤 2013-10-31 10:14 牛武子
          哦  回復  更多評論
            

          # re: jdbc數(shù)據(jù)庫連接丟失或未釋放情況跟蹤[未登錄] 2015-06-17 17:53 1
          專門注冊了個號上來支持下,寫的很好,這個很實用  回復  更多評論
            

          # re: jdbc數(shù)據(jù)庫連接丟失或未釋放情況跟蹤[未登錄] 2015-06-17 17:54 1
          394012149@qq.com  回復  更多評論
            


          只有注冊用戶登錄后才能發(fā)表評論。


          網(wǎng)站導航:
           
          主站蜘蛛池模板: 淮南市| 胶州市| 定结县| 乡城县| 太原市| 平遥县| 利津县| 泗阳县| 邵东县| 台安县| 白河县| 新津县| 四平市| 锦屏县| 宜黄县| 泽普县| 江山市| 揭东县| 繁峙县| 茂名市| 新乐市| 福安市| 麻栗坡县| 徐州市| 宁乡县| 独山县| 临夏县| 扬州市| 济南市| 宝丰县| 大关县| 靖远县| 临夏县| 台中市| 礼泉县| 道孚县| 长汀县| 陵川县| 稻城县| 资溪县| 专栏|