JDBC
提供三種類型的語句對象:
Statement
,
PreparedStatement
,
CallableStatement
。
其中
PreparedStatement
是
Statement
的子類,
CallableStatement
是
PreparedStatement
的子類。每一種語句對象用來運(yùn)行特定類型的
SQL
語句。
Statement
對象用來運(yùn)行簡單類型的
SQL
語句,語句中無需指定參數(shù)。
PreparedStatement
對象用來運(yùn)行包含(或不包含)
IN
類型參數(shù)的預(yù)編譯
SQL
語句。
CallableStatement
對象用來調(diào)用數(shù)據(jù)庫存儲過程。
Statement
1.
概述
Statement
對象用于將
SQL
語句發(fā)送到數(shù)據(jù)庫服務(wù)器。
2.
創(chuàng)建
Statement
對象
建立連接后,
Statement
對象用
Connection
對象的
createStatement
方法創(chuàng)建,以下代碼創(chuàng)建
Statement
對象:
Connection con = DriverManager.getConnection(url, SYSDBA, SYSDBA);
Statement stmt = con.createStatement();
3.
使用
Statement
對象執(zhí)行語句
Statement
接口提供了三種執(zhí)行
SQL
語句的方法:
executeQuery
、
executeUpdate
和
execute
。
方法
executeQuery
用于產(chǎn)生單個結(jié)果集的語句,例如
SELECT
語句。
方法
executeUpdate
用于執(zhí)行
INSERT
、
UPDATE
或
DELETE
語句以及
SQL DDL
語句,如
CREATE TABLE
和
DROP TABLE
。
INSERT
、
UPDATE
或
DELETE
語句的效果是修改表中零行或多行中的一列或多列。
executeUpdate
的返回值是一個整數(shù),表示受影響的行數(shù)。對于
CREATE TABLE
或
DROP TABLE
等
DDL
語句,
executeUpdate
的返回值總為零。
方法
execute
用于執(zhí)行返回多個結(jié)果集、多個更新元組數(shù)或二者組合的語句。
執(zhí)行語句的三種方法都將關(guān)閉所調(diào)用的
Statement
對象的當(dāng)前打開結(jié)果集(如果存在)。這意味著在重新執(zhí)行
Statement
對象之前,需要完成對當(dāng)前
ResultSet
對象的處理。
4.
關(guān)閉
Statement
對象
Statement
對象可由
Java
垃圾收集程序自動關(guān)閉。但作為一種好的編程風(fēng)格,應(yīng)在不需要
Statement
對象時顯式地關(guān)閉它們。這將立即釋放數(shù)據(jù)庫服務(wù)器資源,有助于避免潛在的內(nèi)存問題。
PreparedStatement
1.
概述
PreparedStatement
繼承
Statement
,并與之在兩方面有所不同:
PreparedStatement
對象包含已編譯的
SQL
語句,語句已經(jīng)
“
準(zhǔn)備好
”
。
包含于
PreparedStatement
對象中的
SQL
語句可具有一個或多個
IN
參數(shù)。
IN
參數(shù)的值在
SQL
語句創(chuàng)建時未被指定。相反,該語句為每個
IN
參數(shù)保留一個問號(
“
?
”
)作為占位符。每個問號所對應(yīng)的值必須在該語句執(zhí)行之前,通過適當(dāng)?shù)?/span>
setXXX
方法來提供。
由于
PreparedStatement
對象已預(yù)編譯過,所以其執(zhí)行速度要快于
Statement
對象。因此,需要多次重復(fù)執(zhí)行的
SQL
語句經(jīng)常創(chuàng)建為
PreparedStatement
對象,以提高效率。
作為
Statement
的子類,
PreparedStatement
繼承了
Statement
的所有功能。另外它還添加了一整套方法,用于設(shè)置發(fā)送給數(shù)據(jù)庫以取代
IN
參數(shù)占位符的值。同時,三種方法
execute
、
executeQuery
和
executeUpdate
能執(zhí)行設(shè)置好參數(shù)的語句對象。
2.
創(chuàng)建
PreparedStatement
對象
以下的代碼段(其中
con
是
Connection
對象)創(chuàng)建一個
PreparedStatement
對象:
PreparedStatement pstmt = con.prepareStatement( UPDATE
廠商登記
SET
廠商名
= ? WHERE
廠商編號
= ?);
對象
pstmt
包含語句
UPDATE
廠商登記
SET
廠商名
= ? WHERE
廠商編號
= ?
,該語句帶兩個
IN
參數(shù)占位符,它已發(fā)送給數(shù)據(jù)庫,并由服務(wù)器為其執(zhí)行作好了準(zhǔn)備。
3.
傳遞
IN
參數(shù)
在執(zhí)行
PreparedStatement
對象之前,必須設(shè)置每個
?
參數(shù)的值。這可通過調(diào)用
setXXX
方法來完成,其中
XXX
是與該參數(shù)相應(yīng)的類型。例如,如果參數(shù)具有
Java
類型
String
,則使用的方法就是
setString
。對于不同類型的參數(shù),一般都會有一個推薦的設(shè)置方法和多個可行的設(shè)置方法。
setXXX
方法的第一個參數(shù)是要設(shè)置的參數(shù)的序號(從
1
算起),第二個參數(shù)是設(shè)置給該參數(shù)的值。譬如,以下代碼將第一個參數(shù)設(shè)為
“
中華電視機(jī)廠
”
,第二個參數(shù)設(shè)為
“B0A01”
:
pstmt.setString(1,
中華電視機(jī)廠
);
pstmt.setString(2, B0A01);
每當(dāng)設(shè)置了給定語句的參數(shù)值,就可執(zhí)行該語句。設(shè)置一組新的參數(shù)值之前,應(yīng)先調(diào)用
clearParameters
方法清除原先設(shè)置的參數(shù)值。
4.
使用
setObject
方法
:
可顯式地將輸入?yún)?shù)轉(zhuǎn)換為特定的
JDBC
類型。
該方法可以接受三個參數(shù),其中第三個參數(shù)用來指定目標(biāo)
JDBC
類型。將
Java Object
發(fā)送給數(shù)據(jù)庫之前,驅(qū)動程序?qū)阉D(zhuǎn)換為指定的
JDBC
類型。
如果沒有指定
JDBC
類型,驅(qū)動程序就會將
Java Object
映射到其缺省的
JDBC
類型,然后將它發(fā)送到數(shù)據(jù)庫。這與常規(guī)的
setXXX
方法類似。在這兩種情況下,驅(qū)動程序在將值發(fā)送到數(shù)據(jù)庫之前,會將該值的
Java
類型映射為適當(dāng)?shù)?/span>
JDBC
類型。
二者的差別在于
setXXX
方法使用從
Java
類型到
JDBC
類型的標(biāo)準(zhǔn)映射,而
setObject
方法使用從
Java Object
類型到
JDBC
類型的映射。
方法
setObject
允許接受所有
Java
對象,這使應(yīng)用程序更為通用,并可在運(yùn)行時接受參數(shù)的輸入。這樣,如果用戶在編輯應(yīng)用程序時不能確定輸入類型,可以通過使用
setObject
,對應(yīng)用程序賦予可接受的
Java
對象,然后由
JDBC
驅(qū)動程序自動將其轉(zhuǎn)換成數(shù)據(jù)庫所需的
JDBC
類型。但如果用戶已經(jīng)清楚輸入類型,使用相應(yīng)的
setXXX
方法是值得推薦的,可以提高效率。
5.
將
JDBC NULL
作為
IN
參數(shù)發(fā)送
setNull
方法允許程序員將
JDBC NULL
值作為
IN
參數(shù)發(fā)送給數(shù)據(jù)庫。在這種情況下,可以把參數(shù)的目標(biāo)
JDBC
類型指定為任意值,同時參數(shù)的目標(biāo)精度也不再起作用。
6.
發(fā)送大的
IN
參數(shù)
setBytes
和
setString
方法能夠發(fā)送無限量的數(shù)據(jù)。但是,內(nèi)存要足夠容納相關(guān)數(shù)據(jù)。有時程序員更喜歡用較小的塊傳遞大型的數(shù)據(jù),這可通過將
IN
參數(shù)設(shè)置為
Java
輸入流來完成。當(dāng)語句執(zhí)行時,
JDBC
驅(qū)動程序?qū)⒅貜?fù)調(diào)用該輸入流,讀取其內(nèi)容并將它們當(dāng)作實(shí)際參數(shù)數(shù)據(jù)傳輸。
JDBC
提供了四種將
IN
參數(shù)設(shè)置為輸入流的方法:
setBinaryStream
用于字節(jié)流,
setAsciiStream
用于
ASCII
字符流,
setUnicodeStream
用于
Unicode
字符流,從
JDK1.2
起,輸入字符流的新方法為
setCharacterStream
,而
setAsciiStream
和
setUnicodeStream
已經(jīng)很少用。
7.
獲得參數(shù)元數(shù)據(jù)
JDBC 3.0
實(shí)現(xiàn)了
getParameterMetaData()
方法,通過這個方法可以獲得有關(guān)
IN
參數(shù)的各種屬性信息,比如類型、精度、刻度等信息,類似于結(jié)果集元數(shù)據(jù)的內(nèi)容。通過這些信息,用戶可以更準(zhǔn)確地設(shè)置
IN
參數(shù)的值。
`
在下面的代碼中涉及到了這種方法:
PreparedStatement pstmt = conn.prepareStatement(SELECT * FROM BOOKLIST “ + “WHERE ISBN = ? );
...
//
獲得參數(shù)元數(shù)據(jù)對象
ParameterMetaData pmd = pstmt.getParameterMetaData();
//
獲得參數(shù)的個數(shù)
int paramCount = pstmt.getParameterCount();
//
獲得第一參數(shù)的類型
int colType = pmd.getParameterType(1);
…
8.
自定義方法列表
為了實(shí)現(xiàn)對達(dá)夢數(shù)據(jù)庫所提供的時間間隔類型和帶納秒的時間類型的支持,在實(shí)現(xiàn)
PreparedStatement
接口的過程中,增加了一些自定義的擴(kuò)展方法。用戶將獲得的
PreparedStatement
對象反溯成
DmdbPreparedStatment
類型就可以訪問這些方法。
CallableStatement
1.
概述
CallableStatement
用來運(yùn)行
SQL
存儲過程。存儲過程是數(shù)據(jù)庫中已經(jīng)存在的
SQL
語句,它通過名字調(diào)用。
CallableStatement
是
PreparedStatement
的子類。
CallableStatement
中定義的方法用于處理
OUT
參數(shù)或
INOUT
參數(shù)的輸出部分:注冊
OUT
參數(shù)的
JDBC
類型(一般
SQL
類型)、從這些參數(shù)中檢索結(jié)果,或者檢查所返回的值是否為
JDBC NULL
。
2.
創(chuàng)建
CallableStatement
對象
CallableStatement
對象是用
Connection.prepareCall
創(chuàng)建的。
以下代碼創(chuàng)建
CallableStatement
對象,其中含有對存儲過程
p1
的調(diào)用,
con
為連接對象:
CallableStatement cstmt = con.prepareCall(call p1(?, ?));
其中
?
占位符為
IN
、
OUT
還是
INOUT
參數(shù),取決于存儲過程
p1
。
3. IN
和
OUT
參數(shù)
將
IN
參數(shù)傳給
CallableStatement
對象是通過
setXXX
方法完成的。該方法繼承自
PreparedStatement
。所傳入?yún)?shù)的類型決定了所用的
setXXX
方法(例如,用
setString
來傳入
String
值等)。
如果存儲過程返回
OUT
參數(shù),則在執(zhí)行
CallableStatement
對象之前必須先注冊每個
OUT
參數(shù)的
JDBC
類型,有的參數(shù)還要同時提供刻度。注冊
JDBC
類型是用
registerOutParameter
方法來完成的。語句執(zhí)行完后,
CallableStatement
的
getXXX
方法將取回參數(shù)值。其中
XXX
是為各參數(shù)所注冊的
JDBC
類型所對應(yīng)的
Java
類型。換言之,
registerOutParameter
使用的是
JDBC
類型(因此它與數(shù)據(jù)庫返回的
JDBC
類型匹配),而
getXXX
將之轉(zhuǎn)換為
Java
類型。
設(shè)存儲過程
p1
的定義如下:
CREATE OR REPLACE PROCEDURE p1( a1 IN CHAR(5), a2 OUT CHAR(20)) AS
DECLARE CUR1 CURSOR FOR
SELECT
廠商名
FROM
廠商登記
WHERE
廠商編號
= a1;
BEGIN
OPEN CUR1;
FETCH CUR1 INTO a2;
END;
以下代碼先注冊
OUT
參數(shù),執(zhí)行由
cstmt
所調(diào)用的存儲過程,然后檢索通過
OUT
參數(shù)返回的值。方法
getString
從
OUT
參數(shù)中取出字符串:
CallableStatement cstmt = con.prepareCall(call p1(?, ?));
cstmt.setString(1, B0A05);
cstmt.registerOutParameter(2, java.sql.Types.VARCHAR);
cstmt.executeUpdate();
String x = cstmt.getString(2);
4. INOUT
參數(shù)
如果參數(shù)為既接受輸入又接受輸出的參數(shù)類型(
INOUT
參數(shù)),那么除了調(diào)用
registerOutParameter
方法外,還要調(diào)用對應(yīng)的
setXXX
方法(繼承自
PreparedStatement
)。
setXXX
方法將參數(shù)值設(shè)置為輸入?yún)?shù),而
registerOutParameter
方法將它的
JDBC
類型注冊為輸出參數(shù)。
setXXX
方法提供一個
Java
值,驅(qū)動程序先把這個值轉(zhuǎn)換為
JDBC
值,然后將它送到數(shù)據(jù)庫服務(wù)器。
該
IN
值的
JDBC
類型和提供給
registerOutParameter
方法的
JDBC
類型應(yīng)該相同。如果要檢索輸出值,就要用對應(yīng)的
getXXX
方法。
設(shè)有一個存儲過程
p2
的定義如下:
CREATE OR REPLACE PROCEDURE p2(a1? INOUT? CHAR(20)) AS
DECLARE CUR1 CURSOR FOR
SELECT
廠商名
FROM
廠商登記
WHERE
廠商編號
= a1;
BEGIN
OPEN CUR1;
FETCH CUR1 INTO a1;
END;
以下代碼中,方法
setString
把參數(shù)設(shè)為
“B0A05”
。然后,
registerOutParameter
將該參數(shù)注冊為
JDBC VARCHAR
。執(zhí)行完該存儲過程后,將返回一個新的
JDBC VARCHAR
值。方法
getString
將把這個新值作為
Java
的
String
類型返回。
CallableStatement cstmt = con.prepareCall(call p2(?));
cstmt.setString(1, B0A05);
cstmt.registerOutParameter(1, java.sql.Types.VARCHAR);
cstmt.executeUpdate();
String x = cstmt.getString(1);
5.
利用參數(shù)名進(jìn)行操作
在通常的情況下一般采用參數(shù)索引來進(jìn)行賦值。
JDBC3.0
規(guī)范要求可以利用參數(shù)名來對參數(shù)進(jìn)行賦值,
DM4 JDBC 3.0
驅(qū)動程序?qū)崿F(xiàn)了這一點(diǎn)。如果某個存儲過程的一些參數(shù)有默認(rèn)值,這時候采用參數(shù)名進(jìn)行賦值就非常有用,用戶可以只對那些沒有默認(rèn)值的參數(shù)進(jìn)行賦值。參數(shù)名可以通過調(diào)用
DatabaseMetaData.getProcedureColumns()
來獲得。
下面的代碼中,存儲過程
p2
為上面那個存儲過程
p2
。利用參數(shù)名進(jìn)行操作:
CallableStatement cstmt = con.prepareCall({CALL p2 (?)});
cstmt.setString(a1, B0A05);
cstmt.registerOutParameter(a1, java.sql.Types.VARCHAR);
cstmt.executeUpdate();
String x = cstmt.getString(a1);
而且,在讀取參數(shù)的值和進(jìn)行參數(shù)注冊的時候,
setXXX
、
getXXX
、
registerOutParameter
也都可以采用參數(shù)名來進(jìn)行操作。通過調(diào)用
DatabaseMetaData.supportsNamedParameters()
方法就可以確定
JDBC
驅(qū)動程序是否支持利用參數(shù)名來進(jìn)行操作。
注意:在執(zhí)行同一條語句的過程中,不允許交叉使用參數(shù)索引和參數(shù)名來進(jìn)行操作,否則會拋出異常。
6.
自定義方法列表
為了實(shí)現(xiàn)對達(dá)夢數(shù)據(jù)庫所提供的時間間隔類型和帶納秒的時間類型的支持,在實(shí)現(xiàn)
CallableStatement
接口的過程中,增加了一些自定義的擴(kuò)展方法。用戶將獲得的
CallableStatement
對象反溯成
DmdbCallableStatment
類型就可以訪問這些方法。這些方法所涉及到的擴(kuò)展類請參看
1.2.16
擴(kuò)展類這一節(jié)。
表
1.2.3
:
自定義方法列表
方法名
功能說明
getINTERVALYM(int)
獲取指定列的
DmdbIntervalYM
類型值。
getINTERVALYM(String)
獲取指定列的
DmdbIntervalYM
類型值。
getINTERVALDT(int)
獲取指定列的
DmdbIntervalDT
類型值。
getINTERVALDT(String)
獲取指定列的
DmdbIntervalDT
類型值。
getTIME(int)
獲取指定列的
DmdbTime
類型值。
getTIME(String)
獲取指定列的
DmdbTime
類型值。
setTIME(String, DmdbTime)
根據(jù)參數(shù)名來設(shè)置
DmdbTime
類型值。
setINTERVALDT(String, DmdbIntervalDT)
根據(jù)參數(shù)名來設(shè)置
DmdbIntervalDT
類型值。
setINTERVALYM(String, DmdbIntervalYM)
根據(jù)參數(shù)名來設(shè)置
DmdbIntervalYM
類型值。
ResultSet
1.
概述
ResultSet
提供執(zhí)行
SQL
語句后從數(shù)據(jù)庫返回結(jié)果中獲取數(shù)據(jù)的方法。執(zhí)行
SQL
語句后數(shù)據(jù)庫返回結(jié)果被
JDBC
處理成結(jié)果集對象,可以用
ResultSet
對象的
next
方法以行為單位進(jìn)行瀏覽,用
getXXX
方法取出當(dāng)前行的某一列的值。
通過
Statement
,
PreparedStatement
,
CallableStatement
三種不同類型的語句進(jìn)行查詢都可以返回
ResultSet
類型的對象。
2.
行和光標(biāo)
ResultSet
維護(hù)指向其當(dāng)前數(shù)據(jù)行的邏輯光標(biāo)。每調(diào)用一次
next
方法,光標(biāo)向下移動一行。最初它位于第一行之前,因此第一次調(diào)用
next
將把光標(biāo)置于第一行上,使它成為當(dāng)前行。隨著每次調(diào)用
next
導(dǎo)致光標(biāo)向下移動一行,按照從上至下的次序獲取
ResultSet
行。
在
ResultSet
對象或?qū)?yīng)的
Statement
對象關(guān)閉之前,光標(biāo)一直保持有效。
3.
列
方法
getXXX
提供了獲取當(dāng)前行中某列值的途徑。在每一行內(nèi),可按任何次序獲取列值。
列名或列號可用于標(biāo)識要從中獲取數(shù)據(jù)的列。例如,如果
ResultSet
對象
rs
的第二列名為
“title”
,則下列兩種方法都可以獲取存儲在該列中的值:
String s = rs.getString(title);
String s = rs.getString(2);
注意列是從左至右編號的,并且從
1
開始。
關(guān)于
ResultSet
中列的信息,可通過調(diào)用方法
ResultSet.getMetaData
得到。返回的
ResultSetMetaData
對象將給出其
ResultSet
對象各列的名稱、類型和其他屬性。
4.
采用流方式獲取列值
為了獲取大數(shù)據(jù)量的列,
JDBC
驅(qū)動程序提供了四個獲取流的方法:
getBinaryStream
返回只提供數(shù)據(jù)庫原字節(jié)而不進(jìn)行任何轉(zhuǎn)換的流。
getAsciiStream
返回提供單字節(jié)
ASCII
字符的流。
getUnicodeStream
返回提供雙字節(jié)
Unicode
字符的流。
getCharacterStream
返回提供雙字節(jié)
Unicode
字符的
java.io.Reader
流。
在這四個函數(shù)中,
JDBC
規(guī)范不推薦使用
getCharacterStream
方法,其功能可以用
getUnicodeStream
代替。
5. NULL
結(jié)果值
要確定給定結(jié)果值是否是
JDBC NULL
,必須先讀取該列,然后使用
ResultSet
對象的
wasNull
方法檢查該次讀取是否返回
JDBC NULL
。
當(dāng)使用
ResultSet
對象的
getXXX
方法讀取
JDBC NULL
時,將返回下列值之一:
Java null
值:對于返回
Java
對象的
getXXX
方法(如
getString
、
getBigDecimal
、
getBytes
、
getDate
、
getTime
、
getTimestamp
、
getAsciiStream
、
getUnicodeStream
、
getBinaryStream
、
getObject
等)。
零值:對于
getByte
、
getShort
、
getInt
、
getLong
、
getFloat
和
getDouble
。
false
值:對于
getBoolean
。
6.
結(jié)果集增強(qiáng)特性
在
JDBC
驅(qū)動程序中提供了符合
JDBC 2.0
標(biāo)準(zhǔn)的結(jié)果集增強(qiáng)特性:可滾動、可更新結(jié)果集。及
JDBC3.0
標(biāo)準(zhǔn)的可持有性。
(1)
結(jié)果集的可滾動性
通過執(zhí)行語句而創(chuàng)建的結(jié)果集不僅支持向前(從第一行到最后一行)瀏覽內(nèi)容,而且還支持向后(從最后一行到第一行)瀏覽內(nèi)容的能力。支持這種能力的結(jié)果集被稱為可滾動的結(jié)果集。可滾動的結(jié)果集同時也支持相對定位和絕對定位。絕對定位指的是通過指定在結(jié)果集中的絕對位置而直接移動到某行的能力,而相對定位則指的是通過指定相對于當(dāng)前行的位置來移動到某行的能力。
?JDBC
驅(qū)動程序中支持只向前滾結(jié)果集
(ResultSet.TYPE_FORWARD_ONLY)
和滾動不敏感結(jié)果集
(ResultSet.TYPE_SCROLL_INSENSITIVE)
兩種結(jié)果集類型,不支持滾動敏感結(jié)果集
(ResultSet.TYPE_SCROLL_SENSITIVE)
。當(dāng)結(jié)果集為滾動不敏感結(jié)果集時,它提供所含基本數(shù)據(jù)的靜態(tài)視圖,即結(jié)果集中各行的成員順序、列值通常都是固定的。
(2)
結(jié)果集的可更新性
DM4 JDBC
驅(qū)動程序中提供了兩種結(jié)果集并發(fā)類型:只讀結(jié)果集
(ResultSet.CONCUR_READ_ONLY)
和可更新結(jié)果集
(ResultSet.CONCUR_UPDATABLE)
。采用只讀并發(fā)類型的結(jié)果集不允許對其內(nèi)容進(jìn)行更新。可更新的結(jié)果集支持結(jié)果集的更新操作。
(3)
結(jié)果集的可持有性
JDBC 3.0
提供了兩種結(jié)果集可持有類型:提交關(guān)閉結(jié)果集
(ResultSet.CLOSE_CURSORS_AT_COMMIT)
和跨結(jié)果集提交
(ResultSet.HOLD_CURSORS_OVER_COMMIT)
。采用提交關(guān)閉結(jié)果集類型的結(jié)果集在事務(wù)提交之后被關(guān)閉,而跨結(jié)果集提交類型的結(jié)果集在事務(wù)提交之后仍能保持打開狀態(tài)。
通過
DatabaseMetaData.supportsHoldability()
方法可以確定驅(qū)動程序是否支持結(jié)果集的可持有性。目前
DM4
支持這兩種類型。
(4)
性能優(yōu)化
JDBC
驅(qū)動程序的結(jié)果集對象中提供了方法
setFetchDirection
和
setFetchSize
來設(shè)置缺省檢索結(jié)果集的方向和缺省一次從數(shù)據(jù)庫獲取的記錄條數(shù)。它們的含義與用法和語句對象中的同名函數(shù)是相同的。
7.
更新大對象數(shù)據(jù)
從
JDBC 2.0
驅(qū)動程序就支持可更新的結(jié)果集,但是對
LOB
對象只能讀取,而不能更新,這也是
JDBC 2.0
標(biāo)準(zhǔn)所規(guī)定的。而
JDBC 3.0
規(guī)范規(guī)定用戶可以對
LOB
對象進(jìn)行更新,
DM4 JDBC 3.0
驅(qū)動程序中實(shí)現(xiàn)了這一點(diǎn):
Statement stmt = conn.createStatement(ResultSet.TYPE_FORWARD_ONLY,
ResultSet.CONCUR_UPDATABLE);
ResultSet rs = stmt.executeQuery(select comment from booklist +
where isbn = 140185852);
rs.next();
Clob commentClob = new Clob(...)
;
rs.updateClob(author, commentClob);? // commentClob is a Clob Object
rs.updateRow();
?ResultSetMetaData
1.
概述
ResultSetMetaData
提供許多方法,用于讀取
ResultSet
對象返回數(shù)據(jù)的元信息。包括:列名、列數(shù)據(jù)類型、列所屬的表、以及列是否允許為
NULL
值等,通過這些方法可以確定結(jié)果集中列的一些信息。
2.
創(chuàng)建結(jié)果集元數(shù)據(jù)對象
結(jié)果集元數(shù)據(jù)是用來描述結(jié)果集的特征,所以,需要首先執(zhí)行查詢獲得結(jié)果集,才能創(chuàng)建結(jié)果集元數(shù)據(jù)對象。
3.
創(chuàng)建
ResultSetMetaData
對象如下例所示:
假如有一個表
TESTTABLE(no int,name varchar(10))
,利用下面的代碼就可以知道這個表的各個列的類型:
ResultSet rs = stmt.executeQuery(SELECT * FROM TESTTABLE);
ResultSetMetaData rsmd = rs.getMetaData();
for(int i = 1; i <= rsmd.getColumnCount(); i ++)
{
?? String typeName = rsmd.getColumnTypeName(i);
?? System.out.println(
第
+ i +
列的類型為:
+ typeName);
}
DatabaseMetaData
1.
概述
DatabaseMetaData
提供了許多方法,用于獲取數(shù)據(jù)庫的元數(shù)據(jù)信息。包括:描述數(shù)據(jù)庫特征的信息
(
如是否支持多個結(jié)果集
)
、目錄信息、模式信息、表信息、表權(quán)限信息、表列信息、存儲過程信息等。
DatabaseMetaData
有部分方法以
ResultSet
對象的形式返回結(jié)果,可以用
ResultSet
對象的
getXXX()
方法獲取所需的數(shù)據(jù)。
2.
創(chuàng)建數(shù)據(jù)庫元數(shù)據(jù)對象
數(shù)據(jù)庫元數(shù)據(jù)對象由連接對象創(chuàng)建。以下代碼創(chuàng)建
DatabaseMetaData
對象(其中
con
為連接對象):
DatabaseMetaData dbmd = con.getMetaData();
利用該數(shù)據(jù)庫元數(shù)據(jù)對象就可以獲得一些有關(guān)數(shù)據(jù)庫和
JDBC
驅(qū)動程序的信息:
String databaseName = dbmd.getDatabaseProductName();? //
數(shù)據(jù)庫產(chǎn)品的名稱
int majorVersion = dbmd.getJDBCMajorVersion();? // JDBC
驅(qū)動程序的主版本號
String []types ={TABLE};
ResultSet tablesInfor = dbmd.getTables(null,? null,? “*TE%”,? types);
數(shù)據(jù)類型訪問
1
.概述
對數(shù)據(jù)的訪問主要是
(1)
通過
PreparedStatement
對象、
CallableStatement
對象的
setXXX
方法以及
ResultSet
對象的
updateXXX()
方法進(jìn)行設(shè)置
;
?(2)
通過
CallableStatement
對象、
ResultSet
對象的
getXXX()
方法來進(jìn)行檢索。
2
.各個類型能采用的
setXXX
方法或
updateXXX
方法
請參看
SUN
公司的
JDBC 3.0 specification
文檔第
186
頁的
TABLE-6
。一般地,只要把里面的
getXXX
改為
setXXX
或
updateXXX
即可。
3
.各個類型能采用的
getXXX
方法
請參看
SUN
公司的
JDBC 3.0 specification
文檔第
186
頁的
TABLE-6
。
?ParameterMetaData
1
.概述
參數(shù)元數(shù)據(jù)是
JDBC 3.0
標(biāo)準(zhǔn)新引入的接口,它主要是對
PreparedStatement
、
CallableStatement
對象中的
?
參數(shù)進(jìn)行描述,例如參數(shù)的個數(shù)、參數(shù)的類型、參數(shù)的精度等信息,類似于
ResultSetMetaData
接口。通過引入這個接口,就可以對參數(shù)進(jìn)行較為詳細(xì)、準(zhǔn)確的操作。
2
.創(chuàng)建參數(shù)元數(shù)據(jù)對象
通過調(diào)用
PreparedStatement
或
CallableStatement
對象的
getParameterMetaData()
方法就可以獲得該預(yù)編譯對象的
ParameterMetaData
對象:
ParameterMetaData pmd = pstmt.getParameterMetaData();
然后就可以利用這個對象來獲得一些有關(guān)參數(shù)描述的信息:
//
獲取參數(shù)個數(shù)
int paraCount = pmd.getParameterCount();
for(int i = 1; i <= paraCount; i ++) {
//
獲取參數(shù)類型
System.out.println(The Type of Parameter(+i+) is + ptmt.getParameterType(i));
//
獲取參數(shù)類型名
System.out.println(The Type Name of Parameter(+i+) is
+ ptmt.getParameterTypeName(i));
//
獲取參數(shù)精度
System.out.println(The Precision of Parameter(+i+) is + ptmt.getPrecision(i));
//
獲取參數(shù)是否為空
System.out.println(Parameter(+i+) is nullable? + ptmt.isNullable (i));
}
?
大對象
1
.概述
JDBC
標(biāo)準(zhǔn)為了增強(qiáng)對大數(shù)據(jù)對象的操作,在
JDBC 3.0
標(biāo)準(zhǔn)中增加了
java.sql.Blob
和
java.sql.Clob
這兩個接口。這兩個接口定義了許多操作大對象的方法,通過這些方法就可以對大對象的內(nèi)容進(jìn)行操作。
2
.產(chǎn)生
Lob
對象
在
ResultSet
和
CallableStatement
對象中調(diào)用
getBlob()
和
getClob()
方法就可以獲得
Blob
對象和
Clob
對象:
Blob blob = rs.getBlob(1);
Clob clob = rs.getClob(2);
3
.設(shè)置
Lob
對象
Lob
對象可以像普通數(shù)據(jù)類型一樣作為參數(shù)來進(jìn)行參數(shù)賦值,在操作
PreparedStatement
、
CallableStatement
、
ResultSet
對象時使用:
PreparedStatement pstmt = conn.prepareStatement(INSERT INTO bio (image, text) “ +
“VALUES (?, ?));
//authorImage is a Blob Object
pstmt.setBlob(1, authorImage);
//authorBio is a Clob Object
pstmt.setClob(2, authorBio);
在一個可更新的結(jié)果集中,也可以利用
updateBlob(int,Blob)
和
updateClob(int,Clob)
來更新當(dāng)前行。
4
.改變
Lob
對象的內(nèi)容
Lob
接口提供了方法讓用戶可以對
Lob
對象的內(nèi)容進(jìn)行任意修改:
?
byte[] val = {0,1,2,3,4};
?
Blob data = rs.getBlob(DATA);
int numWritten = data.setBytes(1, val); //
在指定的位置插入數(shù)據(jù)
PreparedStatement ps = conn.prepareStatement(UPDATE datatab SET data = ?);
ps.setBlob(DATA, data);
ps.executeUpdate();
?Savepoint
1
.概述
為了增加對事務(wù)的控制,
JDBC
規(guī)范
3.0
增加了
Savepoint
這個接口。它代表一個邏輯事務(wù)點(diǎn)。在非自動提交模式下,一個事務(wù)中可以設(shè)置多個
Savepoint
。這樣在回滾時,可以回滾到指定的
Savepoint
,從事務(wù)開始到該
Savepoint
之間的操作依然保留著。這就提高了事務(wù)處理的粒度,更好地操縱數(shù)據(jù)。
Savepoint
分為命名的和未命名的兩種。未命名的用系統(tǒng)分配的
ID
作為標(biāo)識。同時可以通過
DatabaseMetaData.supportsSavepoint()
來判斷
JDBC
驅(qū)動程序是否支持
Savepoint
。
2
.操作
Savepoint
Savepoint
的操作位于
Conncetion
接口:
Statement stmt = conn.createStatement();
int rows = stmt.executeUpdate(insert into tab1(col) values(' first') ); //
插入第一條數(shù)據(jù)
Savepoint svpt1 = conn.setSavepoint(SAVEPOINT_1); //
設(shè)置一個
Savepoint
rows = stmt.executeUpdate(intert into tab1(col) values('second') ); //
插入第二條數(shù)據(jù)
……
conn.rollback(svpt1); //
回滾到指定的
Savepoint
……
conn.commit(); //
提交事務(wù)
,
真正在數(shù)據(jù)庫中僅插入了第一條數(shù)據(jù)
這樣,數(shù)據(jù)庫中僅增加了第一次插入的那條記錄。注意:在使用
Savepoint
之前,一定要把當(dāng)前連接設(shè)置為非自動提交模式。
在事務(wù)提交之后,先前事務(wù)中的所有
Savepoint
都自動取消。如果有兩個
Savepoint
,當(dāng)事務(wù)回滾到前面的那個
Savepoint
時,后面的這個
Savepoint
也自動取消。
autoGenerated Key
在很多數(shù)據(jù)庫中,插入一條新的記錄時數(shù)據(jù)庫會為新增的記錄自動產(chǎn)生一個唯一的標(biāo)識。
JDBC3.0
規(guī)范中的
Statement
新增了一個方法:
getGeneratedKeys
,利用這個方法就可以檢索出系統(tǒng)自動為插入的新行所產(chǎn)生的關(guān)鍵字。可以傳遞一個
Statement.RETURN_GENERATED_KEYS
標(biāo)識給
Statement
對象的
execute
、
executeUpdate()
的方法或者
PreparedStatement
對象的一些方法,這樣在執(zhí)行完這些方法之后就可以檢索新產(chǎn)生的關(guān)鍵字。
Statement stmt? = conn.createStatement();
int rows = stmt.executeUpdate(insert into orders(isbn,customerid) values(1953, 'billg') ,
Statement.RETURN_GENERATED_KEYS);
ResultSet rs = stmt.getGeneratedKeys();
boolean b = rs.next();
if (b)
{
//
檢索新產(chǎn)生的關(guān)鍵字的值
……
}
為了檢索方便,用戶也可以為自動產(chǎn)生的關(guān)鍵字指定列名或者索引:
String[] keyColumn = {order_id};
… …
Statement stmt = conn.createStatement();
int rows = stmt.executeUpdate(insert into orders (isbn,customerid) values(9664, 'Billg') ,keyColumn);
ResultSet rs = stmt.getGeneratedKeys();
while(rs.next())
{
//
檢索新產(chǎn)生的關(guān)鍵字的值
byte[] bs = rs.getBytes(order_id);
}
……
JDBC
驅(qū)動程序是否支持自動產(chǎn)生的關(guān)鍵字,可以通過
DataBaseMetaData.supportsGetGeneratedKeys
來判斷。
?
數(shù)據(jù)源
DataSource
數(shù)據(jù)源是
JDBC 2.0
規(guī)范作為擴(kuò)展包引入的,在
JDBC 3.0
規(guī)范中成為核心
API
。數(shù)據(jù)源不僅能夠從功能上完全取代利用
DriverManager
建立連接的方式,而且具有以下幾點(diǎn)優(yōu)勢:
(1)
增強(qiáng)了代碼的可移植性;
(2)
方便了代碼的維護(hù);
(3)
利用連接池來提高系統(tǒng)的性能。
JDBC
驅(qū)動程序提供了對數(shù)據(jù)源的支持,實(shí)現(xiàn)了
javax.sql.DataSource
接口和
java.sql.ConnectionPoolDataSource
接口。用戶通過
javax.sql.DataSource
接口來建立連接。
使用數(shù)據(jù)源來建立連接時,
首先要向
JNDI
注冊一個數(shù)據(jù)源。在建立連接的時候,首先通過
JNDI
來獲得要使用的數(shù)據(jù)源:
DataSource ds = (DataSource) ctx.lookup(datasourceName)
;
然后使用這個數(shù)據(jù)源來建立連接對象:
Connection con = ds.getConnection()
;
該連接同通過
DriverManager
所建立的連接是一樣的。
實(shí)現(xiàn)
javax.sql.ConnectionPoolDataSource
接口是為了提高系統(tǒng)的性能。通過設(shè)置一個連接緩沖區(qū),在其中保持?jǐn)?shù)目較小的物理連接的方式,這個連接緩沖區(qū)由大量的并行用戶共享和重新使用,從而避免在每次需要時建立一個新的物理連接,以及當(dāng)其被釋放時關(guān)閉該連接的昂貴操作。該連接池是
JDBC
提供系統(tǒng)性能的一種措施,是在
JDBC
內(nèi)部實(shí)現(xiàn)的,能夠?yàn)橛脩籼峁┩该鞯母咚倬彌_連接訪問。用戶利用數(shù)據(jù)源來建立連接的應(yīng)用不需為此做出任何代碼上的變動。