6.2. JDBC 数据源概述
JDBC 1.4 标准引入了 javax.sql.DataSource
接口,它充当 java.sql.Connection
对象的 工厂。通常,这些数据源绑定到 JNDI 注册表,并位于 或 servlet 等 Java EE 组件中。关键方面是这些数据源是在 应用服务器 中配置,并按名称在部署的应用程序 中引用。
以下 连接 对象有自己的 数据源 :
数据源 | 连接 |
---|---|
|
|
|
|
|
|
以上每个 数据源 之间最重要的区别如下:
javax.sql.DataSource
最重要的是一个类似于java.sql.Connection
实例的 工厂。大多数javax.sql.DataSource
实现通常执行 连接池 不应更改图片的事实。这是应用程序代码应使用的唯一接口。您正在实施以下哪些方法无关紧要:- 直接 JDBC 访问
-
JPA 持久性单元配置(<
jta-data-source
> 或 <non-jta-data-source>
) - 常见库,如 Apache Camel 或 Spring Framework
javax.sql.ConnectionPoolDataSource
最重要的是通用(特定于数据库)连接池/数据源之间的 桥接。它可以被视为 SPI 接口。应用程序代码通常处理从 JNDI 获取的通用javax.sql.DataSource
对象,并由应用服务器实施(可能使用commons-dbcp2
等库)。在另一个结束时,应用程序代码没有直接与javax.sql.ConnectionPoolDataSource
的接口。它用于应用服务器和特定于数据库的驱动程序。以下序列图显示了这一点:
javax.sql.XADataSource
是一种获取javax.sql.XAConnection
和javax.transaction.xAResource
的方法。与javax.sql.ConnectionPoolDataSource
相同,它在应用服务器和特定于数据库的驱动程序之间使用。以下是带有不同执行器的稍有修改的图表,其中包括 JTA 事务管理器:
如上图中所示,您与 App Server 交互,这是可在其中配置 javax.sql.DataSource
和 javax.transaction.UserTransaction
实例的一般实体。这些实例可以通过 JNDI 进行访问,也可以使用 CDI 或其他依赖项机制注入。
重要的一点是,即使应用使用 XA 事务和/或连接池,应用也会与 javax.sql.DataSource
进行交互,而不是其他 JDBC 数据源接口。
6.2.1. 特定于数据库及通用数据源
JDBC 数据源实施分为两个类别:
通用
javax.sql.DataSource
实现,例如:- Apache Commons DBCP(2)
- Apache Tomcat JDBC(基于 DBCP)
-
javax.sql.DataSource
、javax.sql.XADataSource
和javax.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.ConnectionPoolDataSource
和 javax.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.ConnectionPoolDataSource
javax.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 属性 配置基本的 数据源,如
maxTotal
或minIdle
,用于配置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。