JDBC
驱动开发准则(
Driver Guidelines
)
译者序(
Preface
)
该准则来源“
<<JDBC API Tutorial And Reference,Third Edition>>
中的附录
A
:
For Driver Writers
”。希望能够对大家有所帮助,尤其是开发数据库驱动的,希望能有一个整体的开发概念,根据准则中的描述,深入到每个开发要点和细节,结合实际的
DBMS
作出正确的选择。
作者:
Maydene Fisher,Jon Ellis,Jonathan Bruce
译者:汤泳(
Miker.Tang
)
由于时间的仓促和翻译的不到位,有许多地方值得推敲,请大家及时反馈
tangyong@fnst.com.cn
,谢谢!
对所有驱动的要求
这部分为
JDBC
驱动的标准实现提供了要求。一般地,不要求
JDBC
驱动提供数据库管理系统不支持的特性。
准则(
Guidelines
)
以下的准则适用于
JDBC 1.0,JDBC 2.0
和
JDBC 3.0 API
的实现。
Ø
JDBC API
需要支持
SQL92
标准指定的
SQL
命令。参见“
支持 SQL92扩展标准
”以获取更多的细节。
Ø
驱动必须支持
escape syntax
。“
支持
SQL92
扩展标准
”给予了
escape syntax
更多的细节。
Ø
驱动必须支持事务。
Ø
驱动应该提供对潜在数据源实现的每个特性的访问能力,包括
JDBC API
扩展的特性。当不能支持某个特性时,相应的方法要抛出
SQLException
。目的是对于使用
JDBC API
的应用程序能够访问同样的特性集。
Ø
如果一个
DatabaseMetaData
的方法暗示了支持某个给定的特性,那么就像在相关的规范中描述的那样,通过标准的语法和语义必须要支持。这也许需要驱动提供到数据源原生
API
或不同于标准的
SQL
语义的映射。
Ø
如果支持某个特性,相关的
metadata
方法必须要实现。例如:如果
JDBC API
的实现支持
RowSet
接口,那么也要实现
RowSetMetaData
接口。
Ø
如果不支持某个特性,相应的
DatabaseMetaData
中的方法也必须要给出说明。试图访问不支持的特性将导致
SQLException
被抛出。
在接口中实现方法
JDBC 1.0 API
的接口中所有的方法必须要实现以便至少支持
ANSI SQL 92
和
X/Open SQL CLI
。
JDBC 2.0 API
和
JDBC 3.0 API
必须要实现来支持
ANSI SQL 92,ANSI SQL 99
相关的部分和
X/Open SQL CLI
。
除基本的标准以外,如果
DBMS
不支持某个特性,驱动也不必支持。例如:如果
DBMS
不支持
SQL 99
中的数据类型,那么实现支持这些新的类型(
Array,Blob,Clob,Ref,SQLData,SQLInput,SQLOutput
和
Struct
)的接口就是可选的。或者,如果
DBMS
不支持某个可选包的特性,诸如
connection pooling
,那么支持
connection pooling
(
Connection Event,ConnectionEventListener,ConnectionPoolDataSource,PooledConnection
)的接口就是可选的。如果某个方法支持
DBMS
不包括的特性,那么该方法的实现将抛出
SQLException
。
Metadata
接口应该被完全实现。
DatabaseMetaData
接口的目的是告诉用户
DBMS
支持哪些特性和不支持哪些特性,因此每个方法都要实现。同样地,
ResultSetMetaData
和
ParameterMetaData
接口要完全被实现。提供
javax.sql.RowSet
实现的驱动提供商也应该提供一个
javax.sql.RowSetMetaData
接口的完全实现。
注意:在
JDBC
可选包中的接口已经是
JDBC 3.0 API
的一部分,并且
JDBC
驱动应该实现来作为核心的
JDBC API
。但是,
RowSet
接口和支持它的接口并不包含在里面,因为它们可以实现在
JDBC API
的上层,这样就不作为驱动实现的一部分了。
支持分布式事务的
JDBC
驱动必须支持
XAConnection
和
XADataSource
接口。
兼容
JDBC 1.0 API
的要求
为了兼容
JDBC 1.0 API
,驱动实现需要做以下:
Ø
坚持上面的准则和要求。
Ø
完全实现下列接口:
〇
java.sql.Driver
〇
java.sql.DatabaseMetaData
・
除了在
JDBC 2.0 API
或
JDBC 3.0 API
引入的方法
〇
java.sql.ResultSetMetaData
・除了在
JDBC 2.0 API
或
JDBC 3.0 API
引入的方法
Ø
包括下列所需的接口:
〇 java.sql.CallableStatement
〇 java.sql.Connection
〇 java.sql.PreparedStatement
〇 java.sql.ResultSet
〇 java.sql.Statement
兼容
JDBC 2.0 API
的要求
为了兼容
JDBC 1.0 API
,驱动实现需要做以下:
Ø
符合
JDBC 1.0 API
的要求。
Ø
完全实现
DatabaseMetaData
接口,包括在
JDBC 2.0 API
中增加的下列方法:
〇
deletesAreDetected
〇
getConnection
〇
getUDTs
〇
insertsAreDetected
〇
othersDeletesAreVisible
〇
othersInsertsAreVisible
〇
othersUpdatesAreVisible
〇
ownDeletesAreVisible
〇
ownInsertsAreVisible
〇
ownUpdatesAreVisible
supportsBatchUpdates
supportsResultSetConcurrency
supportsResultSetType
updatesAreDetected
Ø
实现下面
ResultSetMetaData
中其他的方法:
〇 getColumnClassName
〇 getColumnType
〇 getColumnTypeName
兼容
JDBC 3.0 API
的要求
为了兼容
JDBC 3.0 API
,驱动实现需要做以下:
Ø
符合
JDBC 2.0 API
的要求
Ø
包括以下所需的接口:
〇
java.sql.ParameterMetaData
〇
java.sql.Savepoint
Ø
完全实现
DatabaseMetaData
接口,包括在
JDBC 3.0 API
中增加的下列方法:
〇
supportsSavepoints
〇
supportsNamedParameters
〇
supportsMultipleOpenResults
〇
supportsGetGeneratedKeys
〇
getSuperTypes
〇
getSuperTables
〇
getAttributes
〇
getResultSetHoldability
〇
supportsResultSetHoldability
〇
getSQLStateType
〇
getDatabaseMajorVersion
〇
getDatabaseMinorVersion
〇
getJDBCmajorVersion
〇
getJDBCMinorVersion
已经被实现的
API
下面的类和异常在
JDBC 3.0 API
中已经完全被实现了:
·
java.sql.BatchUpdateException
·
java.sql.DataTruncation
·
java.sql.Date
·
java.sql.DriverManager
·
java.sql.DriverPropertyInfo
·
java.sql.SQLException
·
java.sql.SQLPermission
·
java.sql.SQLWarning
·
java.sql.Time
·
java.sql.Timestamp
·
java.sql.Types
·
javax.sql.ConnectionEvent
·
javax.sql.RowSetEvent
其他的要求
除了满足上面列举的要求外,
JDBC
驱动也必须符合下面列举的要求:
实现
Static Initializer
每个
Driver
类应该包含一个特殊的静态区域,有时被称作
Static Initializer
,当使用
DriverManager
来加载
Driver
类时,
Driver
类的
Static Initializer
被调用。当加载
Driver
类时,
Static Initializer
完成以下两件事:
1.
创建
Driver
类的实例。
2.
通过调用
DriverManager.registerDriver
注册新创建的
Driver
实例。
下面的代码演示了
Static Initializer
:
public class MyDriver implements java.sql.Driver {
static {
java.sql.DriverManager.registerDriver(new MyDriver());
}
. . .
}
当完成以上两件事之后,用户通过调用
Class.forName
(
Driver
类名作为参数)方法能够加载和注册
JDBC
驱动。
注意:Static Initializer
仅仅适用使用
DriverManager
加载驱动的方式。通过
DataSource API
加载驱动不会使用
DriverManager
自动地注册,而且在实现上也不应该包含
Static Initializer
。
DriverManager
和
DriverPropertyInfo
类包括
Driver
接口也许在将来会被削弱。
支持
SQL92
扩展标准
支持
Scalar
函数
支持
Scalar
函数需要一些额外的解释。
JDBC
支持数字型,字符串型,时间型,日期型,
System
和转换成
Scalar
值的函数。对于那些想要比“
Statements
中的
SQL Escape Syntax
”更多信息的人来说,
X/Open Group CLI
规范提供了关于
Scalar
函数语义更多的信息。以下是这些函数的列表。
如果
DBMS
支持
Scalar
函数,驱动也应该支持。因为不同的
DBMS
对
Scalar
函数语法上的支持会有不同,所以驱动就是或者将
Scalar
函数映射成合适的语法,或者是在驱动中直接实现这些函数。
用户通过调用
metadata
中的方法应该能发现哪些函数被支持。例如:方法
DatabaseMetaData.getNumericFunctions
应该返回一个逗号分隔的被
Open Group CLI
支持的
numeric
函数列表。类似地,方法
DatabaseMetaData.getStringFunctions
应该返回一个
string
函数列表,等等。
以下是按照种别列出的
Scalar
函数:
NUMERIC FUNCTIONS
Function Name
|
Function Returns
|
ABS(number)
|
Absolute value of
number
|
ACOS(float)
|
Arccosine, in radians, of
float
|
ASIN(float)
|
Arcsine, in radians, of
float
|
ATAN(float)
|
Arctangent, in radians, of
float
|
ATAN2(float1, float2)
|
Arctangent, in radians, of
float2
/
float1
|
CEILING(number)
|
Smallest integer >=
number
|
COS(float)
|
Cosine of
float
radians
|
COT(float)
|
Cotangent of
float
radians
|
DEGREES(number)
|
Degrees in
number
radians
|
EXP(float)
|
Exponential function of
float
|
FLOOR(number)
|
Largest integer <=
number
|
LOG(float)
|
Base e logarithm of
float
|
LOG10(float)
|
Base 10 logarithm of
float
|
MOD(integer1, integer2)
|
Remainder for
integer1
/
integer2
|
PI()
|
The constant
pi
|
POWER(number, power)
|
number
raised to (integer)
power
|
RADIANS(number)
|
Radians in
number
degrees
|
RAND(integer)
|
Random floating point for seed
integer
|
ROUND(number, places)
|
number
rounded to
places
places
|
SIGN(number)
|
・ to indicate
number
is < 0;
0 to indicate
number
is = 0;
1 to indicate
number
is > 0
|
SIN(float)
|
Sine of
float
radians
|
SQRT(float)
|
Square root of
float
|
TAN(float)
|
Tangent of
float
radians
|
TRUNCATE(number, places)
|
number
truncated to
places
places
|
STRING FUNCTIONS
Function Name
|
Function Returns
|
ASCII(string)
|
Integer representing the ASCII code value of the leftmost character in
string
|
CHAR(code)
|
Character with ASCII code value
code
, where
code
is between 0 and 255
|
CONCAT(string1, string2)
|
Character string formed by appending
string2
to
string1
; if a string is null, the result is DBMS-dependent
|
DIFFERENCE(string1, string2)
|
Integer indicating the difference between the values returned by the function
SOUNDEX
for
string1
and
string2
|
INSERT(string1, start, length, string2)
|
A character string formed by deleting
length
characters from
string1
beginning at
start
, and inserting
string2
into
string1
at
start
|
LCASE(string)
|
Converts all uppercase characters in
string
to lowercase
|
LEFT(string, count)
|
The
count
leftmost characters from
string
|
LENGTH(string)
|
Number of characters in
string
, excluding trailing blanks
|
LOCATE(string1, string2[, start])
|
Position in
string2
of the first occurrence of
string1
, searching from the beginning of
string2
; if
start
is specified, the search begins from position
start
. 0 is returned if
string2
does not contain
string1
. Position 1 is the first character in
string2
.
|
LTRIM(string)
|
Characters of
string
with leading blank spaces removed
|
REPEAT(string, count)
|
A character string formed by repeating
string count
times
|
REPLACE(string1, string2, string3)
|
Replaces all occurrences of
string2
in
string1
with
string3
|
RIGHT(string, count)
|
The
count
rightmost characters in
string
|
RTRIM(string)
|
The characters of string with no trailing blanks
|
SOUNDEX(string)
|
A character string, which is data source-dependent, representing the sound of the words in
string
; this could be a four-digit SOUNDEX code, a phonetic representation of each word, etc.
|
SPACE(count)
|
A character string consisting of
count
spaces
|
SUBSTRING(string, start, length)
|
A character string formed by extracting
length
characters from
string
beginning at
start
|
UCASE(string)
|
Converts all lowercase characters in
string
to uppercase
|
TIME and DATE FUNCTIONS
Function Name
|
Function Returns
|
CURDATE()
|
The current date as a date value
|
CURTIME()
|
The current local time as a time value
|
DAYNAME(date)
|
A character string representing the day component of
date
; the name for the day is specific to the data source
|
DAYOFMONTH(date)
|
An integer from 1 to 31 representing the day of the month in
date
|
DAYOFWEEK(date)
|
An integer from 1 to 7 representing the day of the week in
date
; 1 represents Sunday
|
DAYOFYEAR(date)
|
An integer from 1 to 366 representing the day of the year in
date
|
HOUR(time)
|
An integer from 0 to 23 representing the hour component of
time
|
MINUTE(time)
|
An integer from 0 to 59 representing the minute component of
time
|
MONTH(date)
|
An integer from 1 to 12 representing the month component of
date
|
MONTHNAME(date)
|
A character string representing the month component of
date
; the name for the month is specific to the data source
|
NOW()
|
A timestamp value representing the current date and time
|
QUARTER(date)
|
An integer from 1 to 4 representing the quarter in
date
; 1 represents January 1 through March 31
|
SECOND(time)
|
An integer from 0 to 59 representing the second component of
time
|
TIMESTAMPADD(interval, count, timestamp)
|
A timestamp calculated by adding
count
number of
interval
(s) to
timestamp
;
interval
may be one of the following:
SQL_TSI_FRAC_SECOND
,
SQL_TSI_SECOND
,
SQL_TSI_MINUTE
,
SQL_TSI_HOUR
,
SQL_TSI_DAY
,
SQL_TSI_WEEK
,
SQL_TSI_MONTH
,
SQL_TSI_QUARTER
, or
SQL_TSI_YEAR
|
TIMESTAMPDIFF(interval, timestamp1, timestamp2)
|
An integer representing the number of
interval
(s) by which
timestamp2
is greater than
timestamp1
;
interval
may be one of the following:
SQL_TSI_FRAC_SECOND
,
SQL_TSI_SECOND
,
SQL_TSI_MINUTE
,
SQL_TSI_HOUR
,
SQL_TSI_DAY
,
SQL_TSI_WEEK
,
SQL_TSI_MONTH
,
SQL_TSI_QUARTER
, or
SQL_TSI_YEAR
|
WEEK(date)
|
An integer from 1 to 53 representing the week of the year in
date
|
YEAR(date)
|
An integer representing the year component of
date
|
SYSTEM FUNCTIONS
Function Name
|
Function Returns
|
DATABASE()
|
Name of the database
|
IFNULL(expression, value)
|
value
if
expression
is null
; expression
if
expression
is not null
|
USER()
|
User name in the DBMS
|
CONVERSION FUNCTIONS
Function Name
|
Function Returns
|
CONVERT(value, SQLtype)
|
value
converted to
SQLtype
where
SQLtype
may be one of the following SQL types:
BIGINT
,
BINARY
,
BIT
,
CHAR
,
DATE
,
DECIMAL
,
DOUBLE
,
FLOAT
,
INTEGER
,
LONGVARBINARY
,
LONGVARCHAR
,
REAL
,
SMALLINT
,
TIME
,
TIMESTAMP
,
TINYINT
,
VARBINARY
, or
VARCHAR
|
提供
Positioned Updates
和
Deletes
锁定
JDBC 3.0
核心
API
为
position
结果集游标提供了不同的方法,因此,在结果集中很容易更新或删除一个特别的行。但是,
JDBC 1.0 API
仅仅提供了简单的游标支持,这也就使得
positioned Update
或
Delete
有点复杂。
当使用
executeQuery
执行查询的时候,返回结果集且游标位于第一行记录的前面。直到结果集对象或创建该结果集的
Statement
关闭为止,游标将保持有效。如果驱动不支持游标的
position
方法,那么应用程序必须通过调用
ResultSet.getCursorName
方法来获取游标的名称。这个游标的名称能够被使用在
position Update
或
Delete
语句中。
注意:
所有
DBMS
都支持
position Update
和
Delete
。应用程序能够使用
DatabaseMetaData.supportsPositionedUpdate
和
DatabaseMetaData.supportsPostionedDelete
方法来决定当前的连接是否支持。因为许多
DBMS
在
Select
语句(
in Select For Update
)中都不支持“
for update
”,所以驱动必须要检查并且实现这个语义。这个语法(
for update
)的目的是通知生成的结果集将使用
position Update
和
Delete
。
另外,
JDBC 3.0 API
允许应用程序指定结果集对象的持久性(
Holdability
),这就允许在事务过程中创建的结果集对象在事务被提交的生命周期以外被维护。这也意味着
JDBC
驱动必须考虑额外的锁定功能。
当支持
position update
和
delete
时,
DBMS/Driver
必须确保被筛选的行能够被锁定以便
postion update
不会导致更新异常或是其他的并发问题。
支持多线程
java.sql
和
javax.sql
中对象的所有操作都需要多线程的安全。它们必须能正确地处理几个线程同时调用同一个对象。换句话说,在一个线程中执行的命令不应该阻塞在另一个线程中的执行。特别地,当使用多线程时,
JDBC
驱动应该能正确地操作。
一个具体使用多线程的例子是一个长时间运行的命令能够被取消。通过使用一个线程执行该命令而另一个线程能够取消掉来达到目的。
尽管在实际中能够预想决大多数
JDBC
对象将以单线程的方式被访问,但是也需要支持多线程的方式。
一些数据库的
API
,如
ODBC
,提供了异步执行
SQL
语句的机制。这就允许一个应用程序在后台开启数据库的操作,然后处理其他的工作(例如管理用户的接口)来等待后台操作的完成。
因为
Java
编程语言提供了多线程的环境,因此提供异步命令的执行似乎就没有必要了。如果想要异步地执行命令,程序开发人员能够很容易地创建一个隔离的线程。
一些驱动也许允许更多的并发执行,但是开发人员应该能够设想出完全的并发执行场景。如果该驱动需要某种形式的同步,那么驱动应该要提供。在这种情形下,唯一的不同应该是应用程序并发运行的次数会降低。
例如:在同一连接中的两个命令对象能够并发地执行,并且它们的结果集对象能够被并发地处理(从开发者的角度看)。一些驱动将完全提供这种并发能力。其他的也许执行一个命令并且在处理下个结果集之前一直等到第一个处理完成。
为截断的输入参数抛出异常
如果输入的参数被截断,那么
DataTruncation
的异常应该被抛出,参见“
Data Truncation
”,获取更多的信息。
为
SQL99
数据类型使用默认的行为(
JDBC 2.0
)
差异性
由于在数据库功能和语法上的差异,在驱动的实现上
JDBC
允许一些差异。数据库所使用的
SQL
也许不同。例如:对于
Outer Joins
,不同的数据库提供了不同的支持。而且,许多
SQL
特性也许在不同的数据库间存在差异。
Java.sql..DatabaseMetaData
接口提供了许多的方法,通过使用这些方法,用户能够确切地知道当前的数据库支持哪些
SQL
特性。对于驱动开发人员来说,必须确保
DatabaseMetaData
的方法能够返回准确的信息,即
DBMS
支持哪些特性和不支持哪些特性。
处理不支持的功能
当数据库不支持某种功能时,驱动需要作出相应的处理。例如:一些数据库不支持存储过程的
OUT
参数。在这种情形下,
CallableStatement
方法中针对
OUT
参数的方法(
registerOutParameter
和相应的
getter
方法)将不能应用,并且当用户调用时,要抛出
SQLException
。
基本属性的差异
在一些基本的属性方面也允许有差异,例如:事务的隔离级别。当前数据库的默认属性和这些属性的范围可以通过
DatabaseMetaData
的方法获取。
增加的功能
数据库厂商可能会增加额外的功能,这样就会创建
JDBC
类的子类来提供这些额外的功能。例如:
Foobah
公司支持了
SQL99
中的
NCHAR
和
NVCHAR
类型,该公司也许会定义一个新的
JAVA
类型
foobah.sql.FooBahType
来扩展
java.sql.Types
。
驱动的安全性
使用
SQLException
作为异常
如果
DBMS
不支持某个功能,方法中要抛出
SQLException
。
有些情形下,
Java RunTimeException
和
SQLException
也许会重叠。例如:如果一个方法希望一个参数是
java.sql.Types
,结果却提供了其他的类型,那么,
IllegalArgumentException
或
SQLException。这样,推荐抛出SQLException,因为那将给予JDBC更多对Error的控制。
实现的建议
预检索行记录
提供“
Finalize
”方法
避免实现上的依赖
实现
Connection
和
Statement Pooling
在数据库应用程序中获取数据源的连接是一个更加昂贵的操作。因此,为了重用物理连接,实现池化连接的机制能够在性能上提供利益。
JDBC API
提供了一个类(
ConnectionEvent
)和三个接口(
ConnectionEventListener
,
ConnectionPoolDataSource
和
PooledConnection
)来作为连接池的实现策略。
这些
API
决定了连接池如果工作的一般的准则,但是并没有提出连接池如何实现的具体细节。而且,
JDBC 3.0
规范并没有定义在何处实现,留出了很大的实现自由。典型地,一个应用程序服务器将实现连接池和分布式事务的管理。驱动提供商会实现
DataSource
和
ConnectionPoolDataSource
接口以便它们能和实现连接池的
J2EE
应用程序服务器协同工作。如果一个
JDBC
驱动包含了对连接池管理的实现,那么它应该提供一种方式,使得能够关闭驱动的实现。这样,应用程序能够选择使用应用程序服务器的实现,这样可以防止建立两个连接池。
类似地,重用PreparedStatement对象能够增强性能,尤其当prepared statement很大并且要被使用多次的时候。驱动和DBMS也许会花费很多的资源来预编译(原文:precompiling)Statement并且为了执行来准备一个策略,因此为Statement准备一次而不是多次是更加地有效。当创建Statements的连接被池化的时候,Statements也许会被池化。JDBC 3.0规范为ConnectionPoolDataSource增加了一些属性,这些属性能够创建Statement Pool的初始大小,和在池中被维护的Statement的最小数目,等等。这些属性在实现中被设置,并且不是暴露给应用程序开发人员的API一部分。从应用程序开发人员的视角考虑,对于Statement Pooling没有新的API。
实现连接池和
Statement Pooling
必须对用户完全透明。一个例外是驱动应该有关闭自己对连接池实现的能力,以便使用应用程序服务器的实现。应用程序能够透明地创建,使用和关闭连接,不管是否使用了连接池。同样地,应用程序每次创建新的
PreparedStatement
对象的方式也要透明。唯一的不同是如果程序员知道连接池有效,那么他
/
她也许会更好地使用
prepared statements
。但是,一般地,在性能地改善上应用程序会开启使用连接池和
Statement Pooling
。
JDBC
测试套件
驱动提供商通过使用JDBC测试套件能够测试它们的驱动是否和J2EE平台兼容。有两个版本:
·
JDBC Test Suite 1.2.1
: tests for conformance with the JDBC 2.0 API
·
JDBC Test Suite 1.3.1
: tests for conformance with the JDBC 3.0 API
这些测试套件覆盖了经过兼容J2EE测试的驱动功能。它们是免费地并且可以从以下网址下载:
http://java.sun.com/products/jdbc/download.html#jdbctestsuite
如何安装和运行测试套件的文档在以下的网址:
http://java.sun.com/products/jdbc/jdbctestsuite-1_3_1.html
通过测试套件暗示了一个驱动是兼容其他符合J2EE规范的产品,但是并不意味这个驱动能够被标记兼容J2EE。驱动必须要通过一个外部的测试组织来测试是兼容的。完全的驱动认证过程的说明在如下的网址:
http://java.sun.com/products/jdbc/certification.html
The JDBC web pages maintain a database of JDBC drivers, which users can search to find drivers that satisfy their requirements. Search criteria include the type of driver, which versions of the JDBC Specification are supported, and which drivers have been certified to be compatible with the J2EE platform. The database is maintained at
http://java.sun.com/products/jdbc/drivers.html
Drivers may have themselves listed in the database by filling out the submission form at
http://java.sun.com/products/jdbc/add_driver.html
Connectors
(连接器)
在
J2EE
平台上开发应用程序将几乎总想使用
JDBC API
起访问一个或更多
DBMS
。因此,对于驱动提供商来说,能够很容易地将
JDBC
驱动连接到
J2EE
应用程序服务器是件很有趣的事。
J2EE
连接器的架构
J2EE
连接器架构
1.0
规范和
1.5
规范提供了一个框架,能够以一种可插拔(
pluggable
)的方式连接
J2EE
应用程序服务器到额外的资源,例如:
DBMS
。完成这一功能的软件被称作资源适配器(
Resource Adapter
),或者叫
Connector
。
连接器架构的核心是一组契约(
Contracts
)。满足这些契约的驱动实现将能够插入到任何满足这些契约的
J2EE
应用程序服务器中。服务提供接口(
SPI
)契约定义了
J2EE
服务器和资源适配器必须实现的内容,以下是需要实现的领域:
Ø
事务管理(
Transaction management
)
Ø
连接池管理(
Connection pool management
)
Ø
安全性(
Security
)
以下的接口描述了和上述契约等价的服务:
Ø
数据源(DataSource)
Ø
池化的数据源(ConnectionPoolDataSource)
Ø
支持分布式事务的数据源(XADataSource)
DataSource
和
ConnectionPoolDataSource
接口描述了涉及连接池相关的服务。
XADataSource
接口描述涉及分布式事务相关的服务。
JDBC
并没有提供与安全性契约相关的
API
,因为认证总是要包含用户名和密码。
为了使用连接器系统提供的的契约,驱动提供商有不同的选择:
Ø
写一系列的类,用来包装(
Wrap
)
JDBC
驱动并且实现连接器的契约。构建这些包装器相当地直接,并且应该允许提供商足够快地提供资源适配器,以便当应用程序服务器提供商已经实现了连接器契约时能够有用。
Ø
直接实现连接器契约。这样将避免包装带来的负担,但是实现将会更加地耗时和耗力。但是,这是一个长期的选择。
Ø
使用
JDBC
连接器实现。相关的信息可以从以下网址下载:
http://java.sun.com/products/jdbc/related.html
JDBC 3.0
规范,章节
19.3
给出了以连接器资源包(
RAR
)文件格式包裹
JDBC
驱动的细节。下载相关的文档和
RAR
文件解释了
JDBC
连接器如何地工作并且如何地部署它。厂商将会发现使用
SPI RAR
文件非常地容易因为它们不必在驱动实现中改变任何的代码。
The JDBC Connector download includes common client interface (CCI) RAR files as well as SPI RAR files, but they are included more to show what the CCI approach looks like than anything else. Driver vendors will more likely use the SPI RAR files because they make it possible for users to use the JDBC API just as they have always done. The overview document in the JDBC Connector download gives more complete information.