何时不在 Java 中使用数据库连接池?
When NOT to use database connection pooling in Java?
我可以找到很多关于如何使用连接池以及为什么它是个好主意的问题,但我想知道我是否真的需要它。
我正在创建一个服务器应用程序,虽然它是多线程的,但我一直很小心,只有一个线程访问我的数据库连接。
那么使用连接池有什么意义吗?
我不能在生命周期的开始就打开一个到我的数据库的连接并永远使用那个连接,或者如果长时间不活动它会超时吗?
我是否绝对必须在我的连接上调用close()
在我对它做了一些事情之后,还是足够了在 ResultSet
and/or Statement
?
上调用 close()
什么是 "database connection",真的吗?这是与您的数据库的会话,因此:
- 存在客户端和服务器端会话状态
- 有一个与该会话关联的事务
现在,由于您的客户端应用程序是多线程的,我怀疑只有极少数情况下您的设置有意义,即:
- 您不使用会话状态,甚至不小心使用(这可能是特定于供应商的)
- 您不使用事务并且总是自动提交
- 即使自动提交,也可能存在竞争条件,因此您要确保这些不会发生
- 你非常确定每个语句只需要很少时间,释放资源立即
在所有其他情况下,您需要每个客户端线程一个连接,或者在 reactive/async 环境中,您至少需要每个独立的数据库交互一个连接。而且由于创建新连接(即初始化服务器端会话状态等)的成本很高,人们只是使用连接池。事实上,连接池内部只能有一个连接(根据您的要求),它仍然是一个很好的抽象供您使用。那么为什么要编写自己的连接池呢?
关于您的具体问题:
So is there any point in using a connection pool?
除了非常琐碎的情况(见上文),通常有一个连接池是好的。
Can't I just open a connection to my database at the start of the life-cycle and use that one connection forever, or will it time-out if inactive for too long?
当然可以。 JDBC 驱动程序或其他客户端库中通常有一个设置来防止这些超时或重新连接。
这种方法的完美用例是迁移脚本、批处理脚本、简单的测试脚本或简单的 Swing 应用程序等。所有这些都不需要连接池。
Do I absolutely have to call close() on my connection after I do something with it, or is it enough call close() on the ResultSet and/or Statement?
你应该在从DataSource.getConnection()
获得的连接上调用close()
(例如,当连接池实现DataSource
时)。
您不必调用close()
您自己管理其生命周期的连接。
创建数据库连接的成本很高,因此当您有大量通常需要很短时间的请求时,连接池就会发挥作用。您在新上下文中重用先前的数据库连接,以避免为每个请求设置新数据库连接的成本。
避免使用数据库连接的主要原因是您的应用程序解决问题的方法的结构不适合数据库连接池。对于池,某些对使单个共享连接具有高性能的行为有意义的优化可能必须撤消并重新验证以正确采用池并有效地使用池。
此外,虽然许多人担心连接的延迟,但池通过准备好一组连接来减少延迟;您的数据库现在是多个连接的主机这一事实意味着您的应用程序的 "resting" 状态将使用更多资源。通常这不足以在大多数环境中产生很大的不同。
合并的连接有时会启用更多的查询和提交的重新排序,并且在数据库更改时未编写防御性代码来处理数据库状态可能需要额外的返工和验证。请记住,这不是连接池的弱点,而是数据库的数据库处理逻辑中的潜在错误(因为所有数据库都应该被视为共享资源,并且已经进行了这些类型的逻辑检查)。
Can't I just open a connection to my database at the start of the
life-cycle and use that one connection forever, or will it time-out if
inactive for too long?
连接有时会变得陈旧、断开、失败。
许多连接池能够自动检查连接状态、关闭 stale/failed 连接并在需要时重新打开新连接。
考虑网络暂时中断或有人重新启动数据库服务器的情况。
连接池会在发生故障后自动恢复与数据库的连接 - 之后您不必重新启动应用程序。
你可以在你的 dao 中实现这样的功能 class ...但是池已经有了这个,直接使用它更容易。
如果您不想要更多,可以配置仅使用 1 个连接的投票。
我可以找到很多关于如何使用连接池以及为什么它是个好主意的问题,但我想知道我是否真的需要它。
我正在创建一个服务器应用程序,虽然它是多线程的,但我一直很小心,只有一个线程访问我的数据库连接。
那么使用连接池有什么意义吗?
我不能在生命周期的开始就打开一个到我的数据库的连接并永远使用那个连接,或者如果长时间不活动它会超时吗?
我是否绝对必须在我的连接上调用close()
在我对它做了一些事情之后,还是足够了在 ResultSet
and/or Statement
?
close()
什么是 "database connection",真的吗?这是与您的数据库的会话,因此:
- 存在客户端和服务器端会话状态
- 有一个与该会话关联的事务
现在,由于您的客户端应用程序是多线程的,我怀疑只有极少数情况下您的设置有意义,即:
- 您不使用会话状态,甚至不小心使用(这可能是特定于供应商的)
- 您不使用事务并且总是自动提交
- 即使自动提交,也可能存在竞争条件,因此您要确保这些不会发生
- 你非常确定每个语句只需要很少时间,释放资源立即
在所有其他情况下,您需要每个客户端线程一个连接,或者在 reactive/async 环境中,您至少需要每个独立的数据库交互一个连接。而且由于创建新连接(即初始化服务器端会话状态等)的成本很高,人们只是使用连接池。事实上,连接池内部只能有一个连接(根据您的要求),它仍然是一个很好的抽象供您使用。那么为什么要编写自己的连接池呢?
关于您的具体问题:
So is there any point in using a connection pool?
除了非常琐碎的情况(见上文),通常有一个连接池是好的。
Can't I just open a connection to my database at the start of the life-cycle and use that one connection forever, or will it time-out if inactive for too long?
当然可以。 JDBC 驱动程序或其他客户端库中通常有一个设置来防止这些超时或重新连接。
这种方法的完美用例是迁移脚本、批处理脚本、简单的测试脚本或简单的 Swing 应用程序等。所有这些都不需要连接池。
Do I absolutely have to call close() on my connection after I do something with it, or is it enough call close() on the ResultSet and/or Statement?
你应该在从DataSource.getConnection()
获得的连接上调用close()
(例如,当连接池实现DataSource
时)。
您不必调用close()
您自己管理其生命周期的连接。
创建数据库连接的成本很高,因此当您有大量通常需要很短时间的请求时,连接池就会发挥作用。您在新上下文中重用先前的数据库连接,以避免为每个请求设置新数据库连接的成本。
避免使用数据库连接的主要原因是您的应用程序解决问题的方法的结构不适合数据库连接池。对于池,某些对使单个共享连接具有高性能的行为有意义的优化可能必须撤消并重新验证以正确采用池并有效地使用池。
此外,虽然许多人担心连接的延迟,但池通过准备好一组连接来减少延迟;您的数据库现在是多个连接的主机这一事实意味着您的应用程序的 "resting" 状态将使用更多资源。通常这不足以在大多数环境中产生很大的不同。
合并的连接有时会启用更多的查询和提交的重新排序,并且在数据库更改时未编写防御性代码来处理数据库状态可能需要额外的返工和验证。请记住,这不是连接池的弱点,而是数据库的数据库处理逻辑中的潜在错误(因为所有数据库都应该被视为共享资源,并且已经进行了这些类型的逻辑检查)。
Can't I just open a connection to my database at the start of the life-cycle and use that one connection forever, or will it time-out if inactive for too long?
连接有时会变得陈旧、断开、失败。
许多连接池能够自动检查连接状态、关闭 stale/failed 连接并在需要时重新打开新连接。
考虑网络暂时中断或有人重新启动数据库服务器的情况。
连接池会在发生故障后自动恢复与数据库的连接 - 之后您不必重新启动应用程序。
你可以在你的 dao 中实现这样的功能 class ...但是池已经有了这个,直接使用它更容易。
如果您不想要更多,可以配置仅使用 1 个连接的投票。