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.
?