开发人员正在支持一个复杂的Java程序,这个Java程序正在耗尽可用的数据库连接数量.由于问题是零星的,因此知道哪个线程已经打开了与数据库的多个连接来集中在这一领域的努力将是有用的.
最后,正确的修复似乎是重写程序来重用连接,而不是每个线程打开多个连接.
我问,开发人员在他的工具箱中可以使用哪些工具来调查线程分配的资源,即数据库连接.
解决方法
我假设你在java方面使用一致的方法来获取数据库连接(池化或不重要).
这个想法是在连接工厂/池周围创建一个非常轻的包装类,或者它是什么.包装器将实现任何jdbc接口的意义,所以您可以将其交换为正常的连接对象,但大多数方法只会透明地调用/返回底层连接.
如果您使用某种IoC框架(例如spring),您应该可以轻松地在配置级别交换连接/工厂类.现在所有的java代码都将使用你的新数据库连接包装器.
如果你正在使用一个池,那么调用connection.close()通常只是将对象返回给池而不是破坏连接.所以这种技术适用于正常的连接泄漏或只是“不返回池(池用尽)”泄漏.
现在我们只需要记录有趣的位,并为泄漏的连接设置一个陷阱.
堆栈跟踪以识别创建者
在连接包装器的构造函数或工厂方法中,创建一个新的Throwable对象,并将其作为局部变量存储在包装器中以供以后使用.我们使用Throwable,因为它比使用Thread.currentThread().getStackTrace()更快/便宜.
设置“陷阱”
在你的包装类中实现finally方法.当对象因不再使用而被销毁时,这是由GC调用的清理方法.
最后的方法应该检查“我已经关闭了”吗?如果已经关闭了,那么一切都很好…但是如果连接被GC连接并且还没有被关闭,那么这是一个“泄漏的”连接.
现在Throwable回来了.我们可以抓住Throwable,并输出一个不错的日志消息,内容如下所示:“我是一个泄露的连接,这里是一个堆栈跟踪,暗示我的创建者.
扩大想法
这种方法可以适应各种情况.您可以在包装器中保留其他类型的数据,以排除您的具体问题.例如创建时间.那么你可以轮询长期的连接,并再次暗示着创作者.或者,您可以轮询现有连接并解析Throwable堆栈跟踪,以获取哪些代码随时间使用多少连接的数据.
大概可以使用现成的工具,也可以做这些类型的事情,但是在大多数情况下,应用这种技术所需的代码量是非常小的(假设你有一个简单的方法来交换我们的数据库连接工厂,没有搜索 – 替换您的整个代码库).