如今,使用 JDBC 的连接池是不是仍在提高性能?

Posted

技术标签:

【中文标题】如今,使用 JDBC 的连接池是不是仍在提高性能?【英文标题】:Is connection pooling with JDBC still improving performance nowadays?如今,使用 JDBC 的连接池是否仍在提高性能? 【发布时间】:2011-09-26 16:14:14 【问题描述】:

我的应用程序没有使用任何形式的连接池,我直接使用连接。该应用程序主要执行简短的查询。从日志中我可以看到它经常打开和关闭连接,通常只执行一个或几行之间的单选。这些通常需要大约 100 毫秒(包括打开和关闭连接)。

关于连接池如何提高应用程序性能的文章和博客文章数不胜数,但它们似乎都相当陈旧(5 年或更长时间)。

连接池是否仍能提供合理的性能优势,还是已经过时。我正在使用带有 Microsoft JDBC 驱动程序 3.0 版的 SQLServer 2008,如果这很重要的话。


结果/更新:自从我提出这个问题后发生了很多事情(我们切换了 JDBC 驱动程序和许多其他东西)。有时我做了很多重构和其他工作,并且在那个时候还为该应用程序添加了连接池。 通过连接池,一些查询的执行速度现在比日志时间戳粒度可以测量的更快(我相信不到 16 毫秒)。

因此,总而言之,如果您需要频繁连接/断开连接,连接池仍然值得努力。

【问题讨论】:

【参考方案1】:

如果每个查询 100 毫秒适合您,那么您不需要连接池。如果您需要少于 20 毫秒的查询,则重用连接是必不可少的。

如果您的驱动程序支持自己的连接池,我建议您使用它(以防它尚未为您执行此操作)。只有当您想更好地控制连接的池化方式时,您才能使用额外的库(我自己从来没有找到一个很好的用途)

注意:您无需使用池来重用连接。

重用连接的一种简单方法是使用一个持久连接(具有适当的线程安全防护措施)如果您的查询不频繁,这可能就是您所需要的。

如果您希望能够同时执行查询并且只有几个线程可以执行查询,您可以将连接存储在 ThreadLocal 字段中。

如果您需要多个连接,并且执行查询的线程数多于您希望的连接数,请使用池。

对于 ThreadLocal 模型你可以做

public static final ThreadLocal<Connection> CONNECTION = new ThreadLocal<Connection>() 
     public Connection initialValue() 
         LOG.info(Thread.currentThread()+": created a connection.");
         return createConnection();
     
;

如果你想控制如何清理连接。

private static final Map<Thread, Connection> connections = new ConcurrentHashMap();
public static final ThreadLocal<Connection> CONNECTION = new ThreadLocal<Connection>() 
     public Connection initialValue() 
         LOG.info(Thread.currentThread()+": created a connection.");
         Connection conn = createConnection();
         connections.put(Thread.currentThread(), conn);
         return conn;
     
;
public static void cleanUp() 
     for(Map.Entry<Thread, Connection> entry: connections.entrySet()) 
         Thread t = entry.getKey();
         if (!t.isAlive()) 
             LOG.info(t+": closed a connection.");
             connections.remove(t);
             entry.getValue().close();
         
     

如果担心连接死机,可以重写 ThreadLocal 的 get(),在返回前测试连接。

【讨论】:

一个持久连接不起作用,但执行查询的线程数是有限的(我认为它目前设置为 2xCPUS)。在我的情况下,ThreadLocal 的想法可能相当容易实现,尽管在关闭时可能很难正确关闭它们。目前我在连接时间方面没有紧迫的性能问题,但是当客户端使用更广泛时,这可能会改变。 你多久关闭一次线程?你能保持做这个静态的线程数吗?如果没有,您可以拥有Map&lt;Thread, Connection&gt; 的集合,用于查找死线程的连接并关闭它们的连接。 线程仅在运行服务器部分的服务重新启动或终止时关闭,即 JVM 退出时。在实践中,如果我从不清理这些连接,它不会杀了我,我猜。线程数在启动时确定,服务器选择一个随机空闲线程并让它执行所需的任何服务。我唯一的问题是这个线程池不是由我的应用程序维护的,而是一些框架(我必须小心触摸,因为它也被其他应用程序使用)。 当您关闭服务器时,您现在是否明确关闭连接?例如如果您正在使用连接?当你关闭一个应用程序时,它的所有 TCP 连接都会被操作系统关闭(可能不那么干净) 此外 - 无论延迟如何 - 一些 RDBMS 服务器会花费大量精力来建立您的连接。因此,即使延迟对每个客户端来说并不重要,您也会给数据库服务器带来一些可以轻松避免的痛苦。【参考方案2】:

这在一定程度上取决于数据库软件。一些(例如 mysql)具有相对轻量级的连接,可以快速打开。其他的,比如 Oracle,连接是大型的喇叭结构,开销很大。

不过,一般来说,使用连接池是个好主意,尤其是用于快速、简短、大容量的查询。您的应用程序包含连接的速度越快,它就变得越重要。这在过去几年中没有改变 - 如果有的话,它比以往任何时候都更加重要,因为应用程序会扩大规模并变得更加复杂。

如果您需要令人信服,我建议您进行一些基准测试,包括合并和不合并。如果您在特定情况下没有获得性能优势,那么也许不值得费心。

【讨论】:

以上是关于如今,使用 JDBC 的连接池是不是仍在提高性能?的主要内容,如果未能解决你的问题,请参考以下文章

2.5 JDBC连接池

数据库连接池与JDBC的区别

哪个更好:JDBC 连接池,还是使用 SIngleton 类进行 JDBC 连接?

JDBC连接池

C#多线程编程:线程池ThreadPool

MySql & JDBC & 连接池 & 总结