不是特定的工具,而是一种调试技术,用于跟踪哪些代码负责打开连接或其他资源。
我假设您在java端使用一致的方法来获得数据库连接(池化与否无关紧要)。
这个想法是在连接工厂/池或其他任何东西周围创建一个非常轻的包装类。包装器将实现任何有意义的jdbc接口,因此您可以将其交换为普通连接对象,但大多数方法只会透明地调用/返回底层连接。最简单的方法是扩展你的DBConnection类是什么,并且只覆盖你需要监视的特定方法(不要忘记在适当的时候调用)。根据您的实现,您可能需要覆盖工厂以及连接。super.method()
如果您使用的是某种IoC框架(例如spring),您应该能够在配置级别轻松交换连接/工厂类。现在,您的所有 Java 代码都将使用新的 db 连接包装器。
如果您使用的是池,则调用通常只会将对象返回到池中,而不是破坏连接。因此,此技术适用于正常连接泄漏和“未返回到池(池已耗尽)”泄漏。connection.close()
现在,我们只需要记录有趣的位,并为泄漏的连接设置一个陷阱。
用于识别创建者的堆栈跟踪
在连接包装器的构造函数或工厂方法中,创建一个新对象,并将其作为本地/成员变量存储在包装器对象中以供以后使用。我们使用 a,因为它比使用 更快/更便宜。这会记录/牵连请求/建立连接的调用方。Throwable
Throwable
Thread.currentThread().getStackTrace()
Throwable
设置“陷阱”
在包装类中实现该方法。这是 GC 在对象被销毁时调用的清理方法,因为它不再被使用。finalize
该方法应选中“我是否已关闭?如果已经关闭,那么一切都很好...但是,如果连接正在GCed并且尚未关闭...那么这是一个“泄漏”的连接。finalize
现在,它又开始发挥作用了。我们可以获取并输出一条漂亮的日志消息,内容如下:“我是一个泄露的连接,这里有一个堆栈跟踪,暗示我的创建者。Throwable
Throwable
扩展想法
这种方法可以适用于各种情况。当然,您可以将其他类型的数据保留在包装器中,以便对特定问题进行故障排除。例如创建时间。然后,您可以轮询长期连接,并再次牵连创建者。或者,您可以轮询现有连接并分析堆栈跟踪,以获取有关哪些代码在一段时间内使用了多少个连接的数据。Throwable
可能有一个现成的工具也可以做这些类型的事情,但在大多数情况下,应用这种技术所需的代码量非常少(假设你有一个简单的方法来交换我们的数据库连接/工厂,而无需搜索替换你的整个代码库)。但是,如果您需要搜索替换代码库的情况...这是清理代码以使用依赖关系注入的好机会,或者至少是一个中央工厂,您可以在其中更轻松地测试和控制数据库访问。