JDBC 2 以一个附加的 API 的方式引入了标准连接池的特性,这个 附加的 API 叫做 JDBC 2.0 可选包(也称作 JDBC 2.0 标准扩展)。因此这些特性就被包含到核心的 JDBC 3 API 中了。 PostgreSQL JDBC 驱动和 JDK 1.3.x 一起支持这些特性,以及 JDBC 2.0 可选包,或者是和 JDK 1.4+ (JDBC 3)一起,也支持这个特性。大多数应用服务器包含 JDBC 2.0 可选包,但我们也可以从 SUN 单独获得这些东西: JDBC下载站。
JDBC API 为连接池提供了一个客户端和 一个服务器端的接口。客户端接口是 javax.sql.DataSource, 通常就是应用代码用来请求一个缓冲了的数据库连接的东西。 服务器接口是 javax.sql.ConnectionPoolDataSource, 通常是大多数应用服务器和 PostgreSQL JDBC 驱动打交道的接口。
在应用服务器环境里,应用服务器配置通常将指向 PostgreSQL ConnectionPoolDataSource 实现, 而应用组件代码将通常要求一个由应用服务器实现的 DataSource(不是由 PostgreSQL)。
在一个没有应用服务器的环境里,PostgreSQL 提供了 两种应用可以直接使用的 DataSource 的实现。 一种实现执行连接池,另外一种只是简单的通过 DataSource 接口 提供访问数据库的连接,而不使用任何缓冲池。同样,这些实现不应该 在一个应用服务器环境里使用,除非应用服务器不支持 ConnectionPoolDataSource 接口。
PostgreSQL 包含了一个用于 JDBC 2 的 ConnectionPoolDataSource 的实现,以及一个用于 JDBC 3 的实现:
Table 5-1. ConnectionPoolDataSource 实现
JDBC | 实现类 |
---|---|
2 | org.postgresql.jdbc2.optional.ConnectionPool |
3 | org.postgresql.jdbc3.Jdbc3ConnectionPool |
两种实现都使用了同样的配置模式。JDBC 要求一个 ConnectionPoolDataSource 通过 JavaBean 属性来实现, 因此每个这样的属性都存在获取和设置方法:
Table 5-2. ConnectionPoolDataSource 配置属性
属性 | 类型 | 描述 |
---|---|---|
serverName | String | PostgreSQL 数据库服务器主机名 |
databaseName | String | PostgreSQL 数据库名 |
portNumber | int | PostgreSQL 数据库服务器监听的 TCP/IP 端口 (为 0 则使用缺省端口) |
user | String | 用来进行数据库连接的用户 |
password | String | 用来进行数据库连接的口令 |
defaultAutoCommit | boolean | 提交给调用者的时候连接是应该打开 autoCommit 还是应该关闭。 缺省是 false,关闭 autoCommit。 |
许多应用服务器使用属性风格的语法来配置这些属性, 因此把属性当作一块文本输入应该并不罕见。
PostgreSQL 包含两个用于 JDBC 2 的 DataSource,以及两个用于 JDBC 3的。 连接池的实现在客户端调用 close 方法的时候 实际上并不关闭连接,而是把连接返回到一个可用连接的连接池中 给其它客户端使用。这样就避免了任何重复打开和关闭连接造成的 开销,并且允许大量的客户端分享相对较少的数据库连接。
这里提供的连接池 datasource 实现并非世上特性最丰富的。 比如,连接在池本身关闭之前绝对不会关闭;而且也没有办法缩小连接池。 同样,非缺省配置的用户的连接请求无法如池。许多应用服务器提供 更加高级的连接池特性,并且使用的是 ConnectionPoolDataSource 实现。
Table 5-3. DataSource 实现
JDBC | 连接池 | 实现类 |
---|---|---|
2 | 否 | org.postgresql.jdbc2.optional.SimpleDataSource |
2 | 是 | org.postgresql.jdbc2.optional.PoolingDataSource |
3 | 否 | org.postgresql.jdbc3.Jdbc3SimpleDataSource |
3 | 是 | org.postgresql.jdbc3.Jdbc3PoolingDataSource |
所有实现使用同样的配置模式。JDBC 要求 DataSource 通过 JavaBean 属性配置,因此每种这个 属性都有获取和设置属性。
Table 5-4. DataSource 配置属性
属性 | 类型 | 描述 |
---|---|---|
serverName | String | PostgreSQL 数据库服务器主机名 |
databaseName | String | PostgreSQL 数据库名 |
portNumber | int | PostgreSQL 数据库服务器监听的 TCP/IP 端口 (或者 0 表示使用缺省端口) |
user | String | 用于连接数据库的用户 |
password | String | 用于连接数据库的口令 |
连接池实现要求一些额外的配置属性:
Table 5-5. 额外的连接池 DataSource 配置属性
属性 | 类型 | 描述 |
---|---|---|
dataSourceName | String | 每一个连接池 DataSource 必须有一个唯一的名字 |
initialConnections | int | 连接池初始化的时候要创建的数据库连接数目 |
maxConnections | int | 允许打开的最大数据库连接个数。如果请求了更多的连接, 那么调用者将挂起,直到有一个连接返回给连接池。 |
下面是一个使用连接池 DataSource 的典型应用的代码:
Example 5-6. DataSource 代码例子
初始化连接池 DataSource 的代码例子看起来会象这样:
Jdbc3PoolingDataSource source = new Jdbc3PoolingDataSource(); source.setDataSourceName("A Data Source"); source.setServerName("localhost"); source.setDatabaseName("test"); source.setUser("testuser"); source.setPassword("testpassword"); source.setMaxConnections(10);
然后使用来自连接池的代码看起来会象这样。 请注意关闭连接是非常关键的,否则这个池子就会“泄漏”连接, 最后把所有客户端都锁在外面。
Connection con = null; try { con = source.getConnection(); // use connection } catch(SQLException e) { // log error } finally { if(con != null) { try {con.close();}catch(SQLException e) {} } }
所有 ConnectionPoolDataSource 和 DataSource 实现都可以存储在 JNDI 里。在非连接池的实现中, 每次从 JNDI 中检索对象都将创建一个新的实例, 带有和存储的实例同样的设置。对于连接池实现而言,同一个实例 是在可得的情况下检索出来的(也就是说,没有其它 JVM 从 JNDI 中检索连接池),否则就创建同样设置的新的实例。
在应用服务器环境,通常是应用服务器的 DataSource 实例将存储在 JNDI 中,而不是 PostgreSQL ConnectionPoolDataSource 的实现。
在应用服务器环境,应用可以在 JNDI 中存储 DataSource, 这样它就不用制作一个指向 DataSource 的引用提供给 所有可能需要的应用组件使用它:
Example 5-7. DataSource JNDI 代码例子
初始化连接池 DataSource 并且把它加到 JNDI 的代码 看起来可能象这样:
Jdbc3PoolingDataSource source = new Jdbc3PoolingDataSource(); source.setDataSourceName("A Data Source"); source.setServerName("localhost"); source.setDatabaseName("test"); source.setUser("testuser"); source.setPassword("testpassword"); source.setMaxConnections(10); new InitialContext().rebind("DataSource", source);
Then code to use a connection from the pool might look like this:
Connection con = null; try { DataSource source = (DataSource)new InitialContext().lookup("DataSource"); con = source.getConnection(); // use connection } catch(SQLException e) { // log error } catch(NamingException e) { // DataSource wasn't found in JNDI } finally { if(con != null) { try {con.close();}catch(SQLException e) {} } }
在这里包含特定的应用服务器的配置信息。