`
bloodwolf_china
  • 浏览: 129921 次
社区版块
存档分类
最新评论

jdbc数据库连接丢失或未释放情况跟踪

 
阅读更多
  忙碌的工作让我很久没有写过博客了,另外技术上也没有明显的进步,也缺乏兴奋点。项目正式上线很长时间,随要访问压力的增大,每天PV差不多有500万。这时出现了一些问题,主要的是访问响应慢,程序中未发现异常。错误日志有数据库连接的错误,怀疑是数据库连接丢失或有某些请求会锁表。因此写一段代码跟踪数据库连接获取和释放的情况。
   原理很简单,拦截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监控处理
 *
 * @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;
    }

    //创建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方法,记录获取的数据库连接
    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方法,清除释放的数据库连接
    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>

2
1
分享到:
评论

相关推荐

    jsp中jdbc数据库连接

    jdbc连接数据库jdbc连接数据库jdbc连接数据库jdbc连接数据库jdbc连接数据库jdbc连接数据库jdbc连接数据库jdbc连接数据库jdbc连接数据库jdbc连接数据库jdbc连接数据库jdbc连接数据库jdbc连接数据库jdbc连接数据库jdbc...

    jdbc连接数据库jdbc连接数据库

    jdbc连接数据库 jdbc连接数据库 jdbc连接数据库 jdbc连接数据库 jdbc连接数据库

    实现jdbc数据库连接池

    此类非常简单,免去了网上众多资料里所说的麻烦的tomcat配置,更强...不仅oracle,mysql,sqlserver2000都行,因为它依据的是你自己连接数据库的驱动。当然首先你要保证你拥有一个能连接自己数据库的对应驱动类。如下面以

    JDBC连接数据库测试

    JDBC连接数据库测试JDBC连接数据库测试JDBC连接数据库测试JDBC连接数据库测试JDBC连接数据库测试JDBC连接数据库测试JDBC连接数据库测试JDBC连接数据库测试JDBC连接数据库测试JDBC连接数据库测试JDBC连接数据库测试...

    常用jdbc数据库连接jar包,数据库连接池jar包

    收集了常见的数据库连接jar包,包括oracle、mysql、sql server、db2、opta、dbcp连接池、c3p0连接池等等常见的数据库jar包,不断更新中。

    JDBC数据库连接笔记

    JDBC数据库连接笔记

    Java jdbc数据库连接池总结

    在Java语言中,JDBC(Java DataBase Connection)是应用程序与数据库沟通的桥梁

    jdbc数据库连接全部代码

    jdbc数据库连接全部代码 编译环境:MYeclipse~

    JDBC数据库连接JAR包

    JDBC数据库连接JAR包,JDBC数据库连接JAR包

    JDBC数据库连接串总汇

    JDBC连接数据库大全,连接数据库不用急。

    Java-jdbc数据库连接池总结.doc

    Java应用程序访问数据库的基本原理  在Java语言中,JDBC(Java ...JDBC提供两种API,分别是面向开发人员的API和面向底层的JDBC驱动程序API,底层主要通过直接的JDBC驱动和JDBC-ODBC桥驱动实现与数据库的连接。

    java jdbc数据库连接

    java jdbc数据库连接 java jdbc数据库连接 java jdbc数据库连接

    jdbc数据库连接jar包.zip

    Java数据库连接,(Java Database Connectivity,简称JDBC)是Java语言中用来规范客户端程序如何来访问数据库的应用程序接口,提供了诸如查询和更新数据库中数据的方法

    JDBC不同数据库连接

    JDBC不同数据库连接JDBC不同数据库连接JDBC不同数据库连接JDBC不同数据库连接JDBC不同数据库连接

    Java jdbc数据库连接池总结.doc

    Java jdbc数据库连接池Java jdbc数据库连接池Java jdbc数据库连接池Java jdbc数据库连接池

    java_jdbc数据库连接池总结

    java_jdbc数据库连接池总结 有讲原理,不错

    jdbc数据库连接技术

    BaseDao文件中包含了数据库连接技术的URL,DRIVER等。

    java JDBC数据库连接

    这个是JDBC数据库连接的案例,很实用,很容易移植,希望大家喜欢。

    JDBC数据库编程实验

    一、实验目的: ...(5)理解数据库连接池的基本原理和思想,学会在tomcat服务器中配置数据库连接池,并掌握从连接池中获取连接的基本方法。 (6)初步理解数据访问层的基本设计方法,理解web的分层架构。

    JDBC连接数据库步骤

    jdbc java 数据库 连接数据库 步骤

Global site tag (gtag.js) - Google Analytics