忙碌的工作讓我很久沒有寫過博客了,另外技術上也沒有明顯的進步,也缺乏興奮點。項目正式上線很長時間,隨要訪問壓力的增大,每天PV差不多有500萬。這時出現(xiàn)了一些問題,主要的是訪問響應慢,程序中未發(fā)現(xiàn)異常。錯誤日志有數(shù)據(jù)庫連接的錯誤,懷疑是數(shù)據(jù)庫連接丟失或有某些請求會鎖表。因此寫一段代碼跟蹤數(shù)據(jù)庫連接獲取和釋放的情況。
原理很簡單,攔截DataSource的getConnnection方法,把當前Connection和調用堆棧保存到連接列表;攔截Connection對象close方法,把Connection從連接列表中刪除。
直接上代碼:
spring配置文件
寫一個頁面,檢查connections和connectionTime中的對象即可
已有 0 人發(fā)表留言,猛擊->>這里<<-參與討論
ITeye推薦
原理很簡單,攔截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推薦