运用动态代理来检测未close的JDBC Connection 博客分类: Java基础 JDBC编程设计模式SpringHibernate
程序员文章站
2024-03-25 09:05:28
...
虽然spring和Hibernate已经大行其道了。但仍有不少遗留系统,遗留架构仍然是直接采用JDBC编程方式使用数据库的。通常这些架构都会给新人或一些普通技术人员去维护。新人的经验不足,try catch finally三段式编程也就特别容易导致数据库连接未释放。
这类系统通常使用的过程不会导致问题,一旦突发性大访问量,会出现数据库连接池被耗尽的问题,特别是这类系统通常都是一个大系统的某个子系统,“平时不生病,生病要你命”,客户一抱怨就抱怨你整个系统。这类遗留系统的代码通常都不规范,非常难于调试。
所以能有一个快捷跟踪数据库连未被释放的方法仍然是过度时期的上佳选择。
这类代码通常都有一个典型的DBUtils类,用来维护数据库连接。正好可以用来做手术。
先做一个InvocationHandler:
你的DBUtils类,凡是获得Connection的方法都使用如下代码进行包装:
然后没有释放的JDBC连接就无所遁形了。
使用动态代理比直接用Proxy设计模式做个代理类多个好处:兼容不同的JDBC版本。否则,不同JDBC版本的系统要使用不同的代理类,一个字“累”。
这类系统通常使用的过程不会导致问题,一旦突发性大访问量,会出现数据库连接池被耗尽的问题,特别是这类系统通常都是一个大系统的某个子系统,“平时不生病,生病要你命”,客户一抱怨就抱怨你整个系统。这类遗留系统的代码通常都不规范,非常难于调试。
所以能有一个快捷跟踪数据库连未被释放的方法仍然是过度时期的上佳选择。
这类代码通常都有一个典型的DBUtils类,用来维护数据库连接。正好可以用来做手术。
先做一个InvocationHandler:
public class ConnectionInvocationHandler implements InvocationHandler { private static final long serialVersionUID = 321052036610111535L; public final static Timer timer = new Timer("connection-non-close-detector",true); private java.sql.Connection innnerConnection;//实际的连接池里的连接 private TimerTask task; public ConnectionInvocationHandler (Connection conn){ final Exception ex=new Exception(); task=new TimerTask(){ public void run() {//跟踪没有释放的connection调用 ex.printStackTrace(); } }; timer.schedule(task, 5000);//设置其5秒后运行,根据你环境实际情况设置,假如你觉得5秒不够,那就10秒,也就是说10秒还不释放此连接则超时。 this.innnerConnection=conn; } /** * Connection的方法拦截 */ public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { if(method.getName().equals("close")){//关闭close跟踪。 task.cancel(); } Class[] classes=method.getParameterTypes(); return Connection.class.getMethod(method.getName(), classes).invoke(this.innnerConnection, args);//当调用动态代理的方法的时候,真正的connnection的同名方法被调用 } }
你的DBUtils类,凡是获得Connection的方法都使用如下代码进行包装:
Connection conn=.... ..... //the non-closed connect detect code; ConnectionInvocationHandler handler=new ConnectionInvocationHandler (conn); //use dynamic proxy return (Connection) Proxy.newProxyInstance(Connection.class.getClassLoader(), new Class[]{Connection.class}, handler);
然后没有释放的JDBC连接就无所遁形了。
使用动态代理比直接用Proxy设计模式做个代理类多个好处:兼容不同的JDBC版本。否则,不同JDBC版本的系统要使用不同的代理类,一个字“累”。