在部署 J2EE 应用程序中最耗时的操作之一就要数建立到数据库的连接了。应用程序服务器通常提供连接高速缓存或者连接池以尽量减小这一任务所带来的开销。(尽管术语“连接高速缓存”和“连接池”在 JDBC 中有不同的含义,这里我们将借鉴这些术语。)
在 Oracle Application Server Containers for J2EE
这篇技术说明提供了对这一新特性的详细描述,并阐明了它在应用程序中的用法。
OC4J
OC4J
受管理的数据源是由 OC4J 管理的数据源。具体来讲,受管理的数据源就是一个 OC4J 提供的 java.sql.DataSource 实现,充当 JDBC 驱动程序或数据源的绕接器。J2EE 组件通过 JNDI 访问受管理的数据源,而还不知晓该数据源竟是一个绕接器。OC4J 为受管理的数据源提供关键的系统基础架构,如全局事务管理、连接高速缓存、通过 JMX 的动态配置以及错误处理。
原生数据源还实现了 java.sql.DataSource 接口,这些数据源由 JDBC 驱动程序供应商如 Oracle 和 DataDirect 提供。原生数据源根本不用 OC4J 绕接。
下表归纳了受管理的和原生数据源之间的主要差异:
受管理的数据源 原生数据源
从数据源检索到的连接可以参与全局事务 是
否
数据源利用 OC4J 的连接池和语句高速缓存 是 否
从通过一个 OC4J 连接代理绕接的数据源返回的连接 是 否
连接高速缓存
连接高速缓存(通常在中间层实现)允许在不同的应用程序间共享一个数据库连接。 中间层维护着一个预先分配的物理数据库连接池,应用程序可以使用这些连接来与数据库服务器交互。 当应用程序请求数据库连接时,中间层首先查看连接池中是否有符合该请求的可用连接;如果有,则中间层就返回其中的一个连接。
当请求连接而连接高速缓存中没有空闲的池连接实例时,则会创建新的池连接实例。 “空闲”的池连接实例是指该实例当前没有与其相关的逻辑连接实例;换言之,就是指该池连接实例的物理连接没有使用。
当应用程序关闭此连接时,中间层就会把此连接送回到池中,从而避免在发生连接请求执行打开新数据库连接这样耗费大量资源的任务。
高速缓存中的池连接都有一些连接特性或属性(数据库名、服务器名、端口号等等)。大多数连接高速缓存都包括一个连接池,其中包含用于同一数据库和同一用户名的一个或多个连接。
OC4J
OC4J
在 Oracle 数据库
隐式连接高速缓存是数据源的一个新的符合 JDBC 3.0 的连接高速缓存实现。 它通过提供对高速缓存的透明访问,不再需要应用程序开发人员编写自己的高速缓存实现。 它还支持多用户,并能基于用户定义的属性请求连接。
隐式连接高速缓存影响着物理和逻辑连接的概念。 它使用标准 OracleDataSource API 来获得连接,并在底层应用程序启用高速缓存后处理连接缓存中的所有连接。物理连接是由数据库返回的实际连接,而逻辑连接可以看作是高速缓存用于处理物理连接的句柄。
隐式连接高速缓存还提供一个新类 — OracleConnectionCacheManager,这样应用程序就可以使用其丰富的管理 API 组来有效地创建、管理和维护连接高速缓存。应用程序可以通过单个 OracleConnectionCacheManager 实例或者通过与高速缓存相关联的 OracleDataSource 来管理它们的高速缓存。这些 API 广泛应用于 OC4J
还为用户提供了一个回调机制来定义高速缓存行为和确定通过用户定义的连接属性检索到的确切连接。
新的连接高速缓存机制还包括集成的为 Oracle 数据库提供的 RAC 故障切换支持。 它通过监听数据库生成的 UP/DOWN RAC 事件实现了与数据库自身同步的快速、高效的连接高速缓存中连接的连接故障切换。事件发布/订阅机制由 Oracle 通知服务 (ONS) 提供。此类支持只用于 RAC 数据库,这是由于 RAC 数据库支持所需故障切换事件的生成。
与 OC4J
驱动程序独立
连接高速缓存的透明访问
每个缓存可以有多个用户和多个口令
符合 JDBC 3.0 标准
连接回收与陈旧连接的刷新
基于属性搜索连接
启用多个缓存的数据源
连接高速缓存回调机制
集成的对 RAC 快速连接故障切换的支持。
应用程序可以轻松地利用 OC4J
以声明的方式配置连接高速缓存
在 OC4J
受管理的数据源
对于受管理的数据源,配置连接高速缓存可以分两个步骤完成:
使用
在同一文件中的每个
第 2 步相对简单,因此我们集中看第 1 步。
属性名称 说明 默认值
name (Required) The name of the connection pool; must be unique
无
min-connections 连接池将维护的最小连接数
0
max-connections 在任何给定时间能够打开的连接的最大数量。值为 0 或小于 0(表示没有最高限制)。
0
initial-limit
在初次创建或重新初始化高速缓存时设置连接高速缓存的大小。当将该属性设置为大于 0 的值,则可以预先创建许多连接并可随时使用。这个属性通常用于在将缓存设为其最优大小时减少“加速”时间。
0
used-connection-wait-timeout
等待客户端释放使用的连接所需的时间(秒)。该属性只适用于已从数据源获得了最大数量的连接且这些连接都在使用的情形。在这种情况下,当一个客户端尝试从连接池中借一个连接而所有连接都在使用中时,连接池将等待将一个连接释放回池中。
60
inactivity-timeout
将一个未使用的连接从连接池中移除前其不活动的时间(秒)
60
login-timeout
此数据源在尝试连接到一个数据库时将等待的时间的最大值(秒)。值为零说明使用默认的系统超时(如果有的话,否则不会超时)。
0
connection-retry-interval
在重试一个失败的连接尝试前等待的间隔(秒),与“max-connnect-attempts”一起使用
1
max-connect-attempts
重试进行一个连接的次数,与“connection-retry-interval”一起使用
3
validate-connection 表明从连接池借用一个连接时是否根据数据库对其进行验证。值为“true”表明从连接池借用一个连接时,执行由“validate-connection-statement”声明的语句来验证此连接是否有效;值为“false”表明从连接池借用连接时不会执行任何语句。与“validate-connection-statement”一起使用。
false
validate-connection-statement
从连接池借用连接时执行的 SQL 语句。与“validate-connection”一起使用。
无
num-cached-statements 应该为每个连接缓存的最大语句数。任何大于 0 的值自动为数据源启用语句缓存。
0
time-to-live-timeout
一个使用的连接保持活动的最长时间(秒)。 当这个超时时,所使用的连接会无条件地关闭,取消相关语句句柄,并将此连接返回连接池。值为 –1 表示这个特性没有启用。
-1
abandoned-connection-timeout
只适用于 Oracle 数据库。abandoned-connection-timeout 与 inactivity-timeout 类似,但是前者用在逻辑连接上。在设置了该属性时,JDBC 监视这个逻辑连接(由用户从高速缓存借来的连接)上的 SQL 数据库活动。例如,当在此连接上调用 stmt.execute() 时,会注册一个检测信号 (heart beat) 以表示这个连接是活动的。只监视导致数据库执行调用的地方的检测信号以降低监视成本。如果一个连接不活动时间已达到某一指定值,则将底层的 PooledConnection 回收并返回缓存以重新使用。默认值为 -1,即这个特性未生效。
-1
disable-server-connection-pooling
确定是否禁用应用服务器的连接池。之所以提供这个属性是因为一些 JDBC 驱动程序本身就提供了连接池。如果 JDBC 驱动程序是 Oracle 且驱动程序正在使用隐式连接高速缓存,则忽略这个属性。
false
property-check-interval
只适用于 Oracle 数据库。高速缓存后台程序线程执行超时限制的时间间隔(秒)。
900
lower-threshold-limit
只适用于 Oracle 数据库。连接池上较低的阈值限制。默认为 max-connections 的 20%。
20%
除了上面的属性,每个
属性名称 说明 默认值
factory-class (必要)定义连接工厂 (connection-factory) 实现的全路径类。它必须是 java.sql.Driver、javax.sql.DataSource、javax.sql.ConnectionPoolDataSource 或 javax.sql.XADataSource 的一个实现。
无
url (必要)用来连接底层数据库的 url
无
user 用来连接数据库的默认用户
无
password
用来连接数据库的默认口令
无
login-timeout
尝试连接数据库时等待的最长时间(秒)。值为零表示此超时使用默认的系统超时(如果有的话),否则不会超时。
0
现在我们来看一些具体的例子:
使用 XADataSource 连接工厂的受管理数据源
jndi-name="jdbc/ManagedXADS"
description="Managed DataSource"
connection-pool-name="myConnectionPool"
name="ManagedXADS"/>
name="myConnectionPool"
min-connections="10"
max-connections="30"
inactivity-timeout="30"
factory-class="oracle.jdbc.xa.client.OracleXADataSource"
user="scott"
password="tiger"
url="jdbc:oracle:thin:@localhost:1521:oracle"/>
?
使用 DataSource 连接工厂的受管理数据源
jndi-name="jdbc/ManagedDS" description="Managed DataSource"> connection-pool-name="myConnectionPool" name="ManagedDS"/>
name="myConnectionPool"
min-connections="10"
max-connections="30"
inactivity-timeout="30"
factory-class="oracle.jdbc.pool.OracleDataSource"
user="scott"
password="tiger"
url="jdbc:oracle:thin:@localhost:1521:oracle"/>
?
原生数据源
对于原生 Oracle 数据源,配置连接高速缓存主要是以编程的方式完成。(更多详细信息参见接下来的部分。) 连接缓存的声明式配置也可分两个步骤完成:
将“oracle.jdbc.pool.OracleDataSource”用作 data-sources.xml 中每个
在
对于第 2 步,下列属性名称可用于
名称 类型 说明
connectionCacheName String 高速缓存的名称;一旦创建则无法更改。
connectionCachingEnabled Boolean 是否启用隐式连接高速缓存
fastConnectionFailoverEnabled Boolean 是否启用 RAC 快速连接故障切换
下面是一个具体的例子:
name="nativeDataSource"
jndi-name="jdbc/nativeDS"
description="Native DataSource"
data-source-class="oracle.jdbc.pool.OracleDataSource"
user="scott"
password="tiger"
url="jdbc:oracle:thin:@localhost:1521:oracle">
以编程方式配置连接高速缓存
受管理的数据源
在使用受管理的数据源时,连接高速缓存是通过数据源配置文件以声明的方式指定的。 这在“以声明的方式配置连接高速缓存”中有详细说明。
原生数据源
对于 Oracle
对于 (1),OracleDataSource 类为连接高速缓存属性提供下列 setter() 和 getter() 方法:
String getConnectionCacheName()
void setConnectionCacheName(String cacheName)
java.util.Properties getConnectionCacheProperties()
void setConnectionCacheProperties(java.util.Properties cp)
这里的每个连接高速缓存属性对应“以声明的方式配置连接高速缓存”中的受管理数据源情况下的一个配置属性 — 尽管真正的属性名称可能略有不同。
资源
OC4J
OC4J
Oracle
在 Oracle
Oracle
Oracle
Oracle 数据库
Oracle 数据库
保持连接:使用隐式连接高速缓存进行透明的高速缓存访问 作者:Kuassi Mensah
对于 (2),OracleConnectionManager 提供了应用程序可用于管理可用连接高速缓存的 API。 以下是其中的一些 API。(关于 (1) 和 (2) 的更多详细信息,请参考 Oracle 数据库
static OracleConnectionCacheManager getCacheManagerInstance()
void createCache(String cacheName, javax.sql.DataSource ds, Properties cacheProperties)
String createCache(javax.sql.DataSource ds, Properties cacheProperties)
void removeCache(String cacheName, int mode)
void refreshCache(String cacheName, int mode)
java.util.properties getCacheProperties(String cacheName)
下面的 configureDataSource 方法显示了与高速缓存相关联的 OracleDataSource 的一般设置。它用主机名称、用户名称、密码等的相应值配置 Datasource。它还加载一些存储在 Connection.properties 文件中的连接属性:
private void configDataSource(OracleDataSource ods) {
......
/* Load the properties file to get the connection properties
* from the Connection.properties file
*/
Properties prop = this.loadParams("Connection");
ods.setDriverType("thin");
ods.setHostName("localhost");
ods.setNetworkProtocol("tcp");
ods.setPortNumber (1521);
ods.setUser("scott");
ods.setPassword("tiger");
ods.setServiceName("oracle");
ods.setConnectionProperties(prop);
......
}
下面的代码演示上面的方法 (1)。 方法 initializeConnectionCacheDataSrc 启用连接高速缓存,并且设置了高速缓存的名称,该名称唯一地标识该连接高速缓存。然后它在 OracleDataSource 上设置一些连接高速缓存属性,这些属性将被传递给高速缓存。
private void configCachingInDataSource(OracleDataSource ods)
throws SQLException
{
......
ods.setConnectionCachingEnabled(true); // Enable caching
ods.setConnectionCacheName(CACHE_NAME); // Set the cache name
Properties cacheProperties = new Properties();
cacheProperties.setProperty("MinLimit", "1"); // Set Min Limit for the Cache
cacheProperties.setProperty("MaxLimit", "15"); // Set Max Limit for the Cache
cacheProperties.setProperty("InitialLimit", "10"); // Set the Initial Limit
ods.setConnectionCacheProperties(cacheProperties);
}
下面的代码演示上面的方法 (2):如何使用 OracleConnectionCacheManager 创建一个连接高速缓存。 createCache 方法用于创建高速缓存,同时用于接收 OracleDataSource 高速缓存名称和高速缓存 Properties 对象。 请注意,连接高速缓存属性是在创建连接高速缓存时设置的:
private void initializeConnectionCache() throws Exception {
..............
OracleDataSource ods = new OracleDataSource();
this.configureDataSource(ods);
ods.setConnectionCachingEnabled(true); // Enable caching
// Initialize the Connection Cache
OracleConnectionCacheManager connMgr =
OracleConnectionCacheManager.getConnectionCacheManagerInstance();
/* This object holds the properties of a cache and is passed to the
* ConnectionCacheManager while creating the cache.
*/
Properties cacheProperties = new Properties();
cacheProperties.setProperty("MinLimit", "1"); // Set Min Limit for the Cache
cacheProperties.setProperty("MaxLimit", "15"); // Set Max Limit for the Cache
cacheProperties.setProperty("InitialLimit", "10"); // Set the Initial Limit
/* Create the cache by passing the cache name, data source and the
* cache properties
*/
connMgr.createCache(CACHE_NAME, ods, properties);
总结
数据库连接高速缓存是 Oracle 应用服务器一个功能强大的部分。有了 Oracle 数据库