【问题标题】:In an application server environment, should one prefer javax.sql.DataSource or javax.sql.ConnectionPoolDataSource?在应用服务器环境中,应该更喜欢 javax.sql.DataSource 还是 javax.sql.ConnectionPoolDataSource?
【发布时间】:2012-10-01 07:53:02
【问题描述】:

An existing question 表达了类似的意思,但我想在这里指出一个稍微不同的细微差别。

基本问题:所有应用程序服务器都能够指定两个(标准)接口(供应商提供的)实现类(little-d , little-s) 定义连接池时的数据源。如果供应商同时为ConnectionPoolDataSource 和普通的DataSource 提供了实现,那么首选哪一个?

对于在同一个实现类中实现DataSourceConnectionPoolDataSourceXADataSource 的供应商实现呢?

javax.sql.ConnectionPoolDataSource 的文档几乎全部说:

PooledConnection 对象的工厂。实现此接口的对象通常会注册到基于 JavaTM 命名和目录接口 (JNDI) 的命名服务。

这基本上没用,但值得注意的是javax.sql.ConnectionPoolDataSource 本身并没有扩展javax.sql.DataSource,这意味着它的实现不需要提供getConnection() 方法,这是大多数调用者习惯使用的方法。这告诉我所有应用程序服务器必须:

  • javax.sql.DataSource 实现包装javax.sql.ConnectionPoolDataSource 实现,以便调用者可以使用javax.sql.DataSource#getConnection(),或者

  • 检测到javax.sql.ConnectionPoolDataSource 实现也是javax.sql.DataSource 实现,并且(不知何故)相信它的getConnection() 方法将委托给getPooledConnection()(他们到底是如何做到这一点的?)

javax.sql.DataSource 的文档部分说:

DataSource 接口由驱动程序供应商实现。实现方式分为三种:

  • 基本实现 -- 生成标准 Connection 对象
  • 连接池实现——生成一个将自动参与连接池的连接对象。此实现适用于中间层连接池管理器。
  • 分布式事务实现——生成一个可用于分布式事务并且几乎总是参与连接池的连接对象。此实现与中间层事务管理器一起使用,并且几乎总是与连接池管理器一起使用。

这也是无用的,并且启动不正确(或至少未指定:javax.sql.DataSource 也由应用程序服务器供应商实现,他们必须提供一个实现,以便客户端代码可以(例如)将javax.sql.DataSource 注入他们的服务器端代码)。这似乎还暗示任何给定的DataSource 实现可能会或可能不会提供连接池,这让我想知道应用程序服务器应该如何判断何时设置了指定javax.sql.DataSource 接口的连接池(而不是javax.sql.ConnectionPoolDataSource 接口)。

注意:我不是在这里寻找关于我是如何在 Tomcat 上做到这一点的,或者我在 GlassFish 上采取的对我有用的步骤或任何类似性质的答案。我正在寻找一个参考 JDBC 规范、Java EE 规范或错误报告的答案,或者表明这些单独(不相关!)接口存在的原因,以及它们应该如何统一或区分的内容在通用 Java EE 应用程序服务器上,因此有义务提供连接池。

【问题讨论】:

  • +1 表示有趣且具体的问题。

标签: jakarta-ee jdbc


【解决方案1】:

只是为了阐明一点: 我正在使用 Postgres,the API doc from PGConnectionPoolDataSource 对我来说很清楚:

public class PGConnectionPoolDataSource
extends org.postgresql.ds.jdbc4.AbstractJdbc4ConnectionPoolDataSource
implements javax.sql.ConnectionPoolDataSource

ConnectionPoolDataSource 的 PostgreSQL 实现。应用服务器 或中间件供应商应提供一个 DataSource 实现,该实现 利用此 ConnectionPoolDataSource。如果没有,您可以使用 PostgreSQL 实现称为 PoolingDataSource,但是 仅应在您的服务器或中间件供应商不提供的情况下使用 提供自己的。为什么?服务器可能希望重用相同的 跨所有请求连接的 EJB 的连接 交易,或提供其他类似的高级功能。

【讨论】:

  • 感谢您的回答。请阅读下面我与 Mark 的对话,因为从应用服务器供应商的角度来看,事情还不清楚。
【解决方案2】:

您不应直接使用ConnectionPoolDataSource,它旨在作为物理连接(又名PooledConnections)的源,然后由实际实现连接池的DataSource 使用。 ConnectionPoolDataSource 不应该实际实现池本身。

这样的 DataSource 例如由您的应用程序服务器提供。它通常需要一个 JNDI url(或直接引用)到 ConnectionPoolDataSource,并且它本身公开了 DataSource 接口来分发“逻辑”连接。

DataSources 在JDBC 4.1 9.4 节中讨论:

DataSource 接口 [..] 是获取数据源连接的首选方法。

逻辑名称通过使用 Java 命名和目录接口 (JNDI) 的命名服务映射到数据源对象。 DataSource 对象代表一个物理数据源并提供与该数据源的连接。

如果我们再看一下引言中对连接池的描述(第 11 章)指定:

JDBC 驱动程序提供了 ConnectionPoolDataSource 的实现,应用程序服务器使用它来构建和管理连接池。

用于管理连接池的算法是特定于实现的,并且 因应用服务器而异。 应用服务器为其客户端提供一个 实现连接池的 DataSource 接口 对客户透明。结果,客户端获得了更好的性能和 可扩展性,同时使用与以前相同的 JNDI 和 DataSource API。 (强调我的)

(AS)DataSource(以下简称:ASDS)和(驱动程序)ConnectionPoolDataSource(以下简称 CPDS)之间的交互在第 11.1 - 11.3 节中进行了描述。 11.3 节具体描述了交互:

以下步骤序列概述了当 JDBC 客户端从实现的 DataSource 对象请求连接 连接池:

  • 客户端调用DataSource.getConnection。
  • 提供 DataSource 实现的应用程序服务器在其连接池中查找是否有合适的 PooledConnection 对象——一个物理数据库连接——可用​​。 确定给定 PooledConnection 对象的适用性可能 包括匹配客户端的用户身份验证信息或 应用程序类型以及使用其他特定于实现的 标准。与管理相关的查找方法和其他方法 连接池特定于应用程序服务器。
  • 如果没有合适的 PooledConnection 对象可用,应用程序服务器将调用 ConnectionPoolDataSource.getPooledConnection 方法获取一个新的 物理连接。 JDBC驱动实现 ConnectionPoolDataSource 创建一个新的 PooledConnection 对象和 将其返回给应用服务器。
  • 无论 PooledConnection 是从池中检索到的还是新创建的,应用程序服务器都会执行一些内部操作 记账以指示物理连接现在正在使用中。
  • 应用服务器调用方法PooledConnection.getConnection 获取逻辑Connection 对象。 这个逻辑连接对象实际上是一个物理的“句柄” PooledConnection 对象,正是这个句柄由 连接池生效时的 DataSource.getConnection 方法。
  • 应用服务器通过调用方法将自己注册为ConnectionEventListener PooledConnection.addConnectionEventListener。这样做是为了使 应用程序服务器将在 PooledConnection 对象时收到通知 可重复使用。
  • 逻辑 Connection 对象返回给 JDBC 客户端,它使用与基本 DataSource 案例中相同的 Connection API。笔记 底层的 PooledConnection 对象不能被重用,直到 客户端调用 Connection.close 方法。

最后一项并不完全正确:ASDS 可以通过分发从同一 PooledConnection 获得的新 Connection 来强制关闭/使来自客户端的逻辑连接无效(参见第 11.4 节)。

现在在评论中提出您的问题:为什么 AS 允许您在数据源配置中同时指定 DataSourceConnectionPoolDataSource 接口:ASDS 和 CPDS 之间的引用通常也通过 JNDI 完成.例如,这允许轻松重新配置(将 ASDS 切换到不同的底层 CPDS,或将 ASDS 切换到正常的基本数据源,同时仍保持 CPDS 的配置,例如因为它也被不同的 ASDS 使用)。另请参阅 JDBC 规范的第 11.5 节:

部署实现连接池的 DataSource 对象要求客户端可见的 DataSource 对象和底层 ConnectionPoolDataSource 对象都注册到基于 JNDI 的命名服务。

【讨论】:

  • 好的,我们需要非常精确。如果你是对的,那么所有应用服务器供应商都错了,因为他们都让你指定你的数据源(little-d、little-s)可以实现的javax.sql.*接口,并且是所有应用服务器上的有效选择之一是ConnectionPoolDataSource。确实,在 client 代码中,您总是使用javax.sql.DataSource 来获得 JDBC 连接,但这不是我要说的。
  • (因为我无法编辑我之前的评论...)想确保您明白我不是在谈论在客户端代码中使用javax.sql.ConnectionPoolDataSource。我说的是在应用服务器上设置数据源(little-d、little-s)。在这一点上,所有应用程序服务器让我选择我的驱动程序是否应该在数据源设置时将自己暴露为javax.sql.DataSourcejavax.sql.ConnectionPoolDataSourcejavax.sql.XADataSource。我知道什么时候应该选择后者。我不确定如何在前两者之间进行选择,也没有文档可以提供帮助。
  • 我认为不幸的是它没有。我很欣赏规范参考,这似乎暗示(但仍然没有明确说明)当我设置新的 little-d 数据源时,如果我的驱动程序提供,我应该更喜欢 ConnectionPoolDataSource 实现它。然后不幸的是,您的最后一段再次提出了问题。
  • 我不确定最后一段是如何再次打开这个问题的。 JDBC 规范试图通过该段落传达的内容是:1)在 JNDI 中设置 ConnectionPoolDataSource,2)在 JNDI 中设置(AS)DataSource,使用步骤 1 中 CPDS 的 JNDI 引用,最后 3)使用应用程序中第 2 步的 ASDS。参见例如this blog,特别是第 5 步(对应于我的第 1 步)、10(对应于我的第 2 步)和 11(几乎对应于我的第 3 步)
  • 谢谢。现在我们有了可以讨论的步骤。我对博客的第 10 步(您的第 2 步)不感兴趣,因为用 GlassFish 的说法是创建 JDBC 资源,这与创建连接池是分开的。此外,在创建 JDBC 资源时,没有选择javax.sql.* 接口的选项。我对博客第 11 步(您的第 3 步)也不感兴趣,因为那是客户端代码。所以我只对博客第 5 步(你的第 1 步)感兴趣。在博客中,他在这里选择了ConnectionPoolDataSource,但他本可以选择javax.sql.DataSource。他为什么会做出这样的选择?
猜你喜欢
  • 2015-06-13
  • 2013-12-13
  • 1970-01-01
  • 1970-01-01
  • 2012-09-04
  • 2011-11-29
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多