6.2. JDBC 数据源概述

JDBC 1.4 标准引入了 javax.sql.DataSource 接口,它充当 java.sql.Connection 对象的 工厂。通常,这些数据源绑定到 JNDI 注册表,并位于 或 servlet 等 Java EE 组件中。关键方面是这些数据源是在 应用服务器 中配置,并按名称在部署的应用程序 中引用

以下 连接 对象有自己的 数据源

数据源连接

javax.sql.DataSource

java.sql.Connection

javax.sql.ConnectionPoolDataSource

javax.sql.PooledConnection

javax.sql.XADataSource

javax.sql.XAConnection

以上每个 数据源 之间最重要的区别如下:

  • javax.sql.DataSource 最重要的是一个类似于 java.sql.Connection 实例的 工厂。大多数 javax.sql.DataSource 实现通常执行 连接池 不应更改图片的事实。这是应用程序代码应使用的唯一接口。您正在实施以下哪些方法无关紧要:

    • 直接 JDBC 访问
    • JPA 持久性单元配置(< jta-data-source > 或 &lt ;non-jta-data-source>
    • 常见库,如 Apache Camel 或 Spring Framework
  • javax.sql.ConnectionPoolDataSource 最重要的是通用(特定于数据库)连接池/数据源之间的 桥接。它可以被视为 SPI 接口。应用程序代码通常处理从 JNDI 获取的通用 javax.sql.DataSource 对象,并由应用服务器实施(可能使用 commons-dbcp2等库)。在另一个结束时,应用程序代码没有直接与 javax.sql.ConnectionPoolDataSource 的接口。它用于应用服务器和特定于数据库的驱动程序。以下序列图显示了这一点:

    diag 7f73f899365cf56b8aa906191213fa81
  • javax.sql.XADataSource 是一种获取 javax.sql.XAConnectionjavax.transaction.xAResource 的方法。与 javax.sql.ConnectionPoolDataSource 相同,它在应用服务器和特定于数据库的驱动程序之间使用。以下是带有不同执行器的稍有修改的图表,其中包括 JTA 事务管理器:

    diag ebfce784cac352c984238fe0a82ca4fa

如上图中所示,您与 App Server 交互,这是可在其中配置 javax.sql.DataSourcejavax.transaction.UserTransaction 实例的一般实体。这些实例可以通过 JNDI 进行访问,也可以使用 CDI 或其他依赖项机制注入。

重要

重要的一点是,即使应用使用 XA 事务和/或连接池,应用也会与 javax.sql.DataSource 进行交互,而不是其他 JDBC 数据源接口。

6.2.1. 特定于数据库及通用数据源

JDBC 数据源实施分为两个类别:

  • 通用 javax.sql.DataSource 实现,例如:

  • javax.sql.DataSourcejavax.sql.XADataSourcejavax.sql.ConnectionPoolDataSource的数据库具体实施

常见 javax.sql.DataSource 实现可能会令人困惑,无法自行创建特定于数据库的连接。即使 通用 数据源可以使用 java.sql.Driver.connect()java.sql.DriverManager.getConnection(),通常最好使用特定于数据库的 javax.sql.DataSource 实现配置此 通用 数据源。

通用 数据源与 JTA 交互时,它 必须配置有 javax.sql.XADataSource 的数据库特定实施。

要关闭图片,通用 数据源 通常不需要 特定于数据库的 javax.sql.ConnectionPoolDataSource 来执行连接池。现有池通常处理没有标准 JDBC 接口(javax.sql.ConnectionPoolDataSourcejavax.sql.PooledConnection)的池,而是使用自己的自定义实施。

6.2.2. 有些通用数据源

例如,众所周知的通用数据源 Apache Commons DBCP(2).

javax.sql.XADataSource 实现

DBCP2 不包括 javax.sql.XADataSource 的任何实施,这是预期的。

javax.sql.ConnectionPoolDataSource implementations

DBCP2 确实 包括 javax.sql.ConnectionPoolDataSource 的实施:org.apache.commons.dbcp2.cpdsadapter.DriverAdapterCPDS。它通过调用 java.sql.DriverManager.getConnection() 创建 javax.sql.PooledConnection 对象。这个池不应该被直接使用,它应该被视为 驱动程序的适配器

  • 不要提供自己的 javax.sql.ConnectionPoolDataSource 实现
  • 您需要根据 JDBC 建议用于 连接池来使用

如上图中所示,驱动程序直接提供 javax.sql.ConnectionPoolDataSource,或利用 org.apache.commons.dbcp2.cpdsadapter.DriverAdapterCPDS 适配器的 帮助,而 DBCP2 实施了 应用服务器 合同之一:

  • org.apache.commons.dbcp2.datasources.PerUserPoolDataSource
  • org.apache.commons.dbcp2.datasources.SharedPoolDataSource

这两个池均在配置阶段获取 javax.sql.ConnectionPoolDataSource 的实例。

这是 DBCP2 中最重要的和有趣的部分:

javax.sql.DataSource 实现

要实现连接池功能,您不必遵循 JDBC 建议 以使用 javax.sql.ConnectionPoolDataSourcejavax.sql.PooledConnection SPI。

以下是 DBCP 2 的一般数据源列表:

  • org.apache.commons.dbcp2.BasicDataSource
  • org.apache.commons.dbcp2.managed.BasicManagedDataSource
  • org.apache.commons.dbcp2.PoolingDataSource
  • org.apache.commons.dbcp2.managed.ManagedDataSource

这里有 两个问题

基本

这个 axis 决定 池配置 方面。

两种数据源都执行 java.sql.Connection 对象的 唯一的 区别是:

  • 使用 bean 属性 配置基本的 数据源,如 maxTotalminIdle,用于配置 org.apache.commons.pool2.impl.GenericObjectPool 的内部实例。
  • 数据源配置有外部创建/配置的 org.apache.commons.pool2.ObjectPool

受管 与非管理

这个 axis 决定 连接创建 信息以及 JTA 行为:

  • 非管理的基本 数据源在内部使用 java.sql.Driver. Driver.connect()创建 java.sql. Connection 实例。

    非管理的池 数据源使用传递的 org.apache.commons.pool2.ObjectPool 对象来创建 java.sql.Connection 实例。

  • 受管池 数据源将 java.sql.Connection 实例嵌套在 org.apache.commons.dbcp2.managed.ManagedConnection 对象,以确保 JTA 上下文中需要调用 javax.transaction.Transaction.enlistResource()。但是,仍从池配置的任何 org.apache.commons.pool2.ObjectPool 对象获取已嵌套的实际连接。

    受管的基本 数据源可从配置专用 org.apache.commons.pool2.ObjectPool。相反,配置现有的、真实的、特定于数据库的 javax.sql.XADataSource 对象就足够了。bean 属性用于创建 org.apache.commons.pool2.impl.GenericObjectPool 的内部实例,后者被传递给 受管 池数据源(org.apache.commons.dbcp2.managed.ManagedDataSource)的内部实例。

注意

DBCP2 唯一无法执行的事情是 XA 事务恢复。DBCP2 正确放入活跃 JTA 事务中的 XAResources,但不执行恢复。这应该单独完成,配置通常特定于所选交易管理器实施(如 Narayana)。

6.2.3. 要使用的模式

推荐的模式是:

  • 创建或获取带有特定 数据库 的配置(URL、凭证等)的、特定于数据库的 javax.sql.XADataSource 实例,或获取可以创建连接/XA 连接的数据库。
  • 创建或获取 非特定于数据库的 javax.sql.DataSource 实例(内部配置了上述、特定于数据库的数据源),具有非特定于数据库的配置(连接池、事务管理器等)。
  • 使用 javax.sql.DataSource 获取 java.sql.Connection 的实例并执行 JDBC 操作。

以下是一个 规范的示例

// Database-specific, non-pooling, non-enlisting javax.sql.XADataSource
PGXADataSource postgresql = new org.postgresql.xa.PGXADataSource();
// Database-specific configuration
postgresql.setUrl("jdbc:postgresql://localhost:5432/reportdb");
postgresql.setUser("fuse");
postgresql.setPassword("fuse");
postgresql.setCurrentSchema("report");
postgresql.setConnectTimeout(5);
// ...

// Non database-specific, pooling, enlisting javax.sql.DataSource
BasicManagedDataSource pool = new org.apache.commons.dbcp2.managed.BasicManagedDataSource();
// Delegate to database-specific XADatasource
pool.setXaDataSourceInstance(postgresql);
// Delegate to JTA transaction manager
pool.setTransactionManager(transactionManager);
// Non database-specific configuration
pool.setMinIdle(3);
pool.setMaxTotal(10);
pool.setValidationQuery("select schema_name, schema_owner from information_schema.schemata");
// ...

// JDBC code:
javax.sql.DataSource applicationDataSource = pool;

try (Connection c = applicationDataSource.getConnection()) {
    try (Statement st = c.createStatement()) {
        try (ResultSet rs = st.executeQuery("select ...")) {
            // ....

在 Fuse 环境中,有很多配置选项且不需要使用 DBCP2。