當獲得了與數(shù)據(jù)庫的連接后,就可以與數(shù)據(jù)庫進行交互了。 JDBC Statement
,CallableStatement
和PreparedStatement
接口定義了可用于發(fā)送SQL或PL/SQL命令,并從數(shù)據(jù)庫接收數(shù)據(jù)的方法和屬性。
它們還定義了有助于在Java和SQL數(shù)據(jù)類型的數(shù)據(jù)類型差異轉(zhuǎn)換的方法。
下表提供了每個接口定義,以及使用這些接口的目的的總結(jié)。
接口 | 推薦使用 |
---|---|
Statement |
用于對數(shù)據(jù)庫進行通用訪問,在運行時使用靜態(tài)SQL語句時很有用。 Statement 接口不能接受參數(shù)。 |
PreparedStatement |
當計劃要多次使用SQL語句時使用。PreparedStatement 接口在運行時接受輸入?yún)?shù)。 |
CallableStatement |
當想要訪問數(shù)據(jù)庫存儲過程時使用。CallableStatement 接口也可以接受運行時輸入?yún)?shù)。 |
在使用Statement
對象執(zhí)行SQL語句之前,需要使用Connection
對象的createStatement()
方法創(chuàng)建一個Statement
對象,如以下示例所示:
Statement stmt = null;
try {
stmt = conn.createStatement( );
. . .
}
catch (SQLException e) {
. . .
}
finally {
. . .
}
在創(chuàng)建Statement
對象后,可以使用它來執(zhí)行一個SQL語句,它有三個執(zhí)行方法可以執(zhí)行。它們分別是 -
boolean execute (String SQL)
: 如果可以檢索到ResultSet
對象,則返回一個布爾值true
; 否則返回false
。使用此方法執(zhí)行SQLDDL
語句或需要使用真正的動態(tài)SQL,可使用于執(zhí)行創(chuàng)建數(shù)據(jù)庫,創(chuàng)建表的SQL語句等等。int executeUpdate (String SQL):
返回受SQL語句執(zhí)行影響的行數(shù)。使用此方法執(zhí)行預期會影響多行的SQL語句,例如:INSERT
,UPDATE
或DELETE
語句。ResultSet executeQuery(String SQL):
返回一個ResultSet
對象。 當您希望獲得結(jié)果集時,請使用此方法,就像使用SELECT
語句一樣。就像關(guān)閉一個Connection
對象一樣,以保存數(shù)據(jù)庫資源一樣,由于同樣的原因,還應該關(guān)閉Statement
對象。
一個簡單的調(diào)用close()
方法將執(zhí)行該作業(yè)(工作)。 如果先關(guān)閉Connection
對象,它也會關(guān)閉Statement
對象。 但是,應該始終顯式關(guān)閉Statement
對象,以確保正確的清理順序。
Statement stmt = null;
try {
stmt = conn.createStatement( );
. . .
}
catch (SQLException e) {
. . .
}
finally {
stmt.close();
}
為了更好的理解,建議學習Statment示例教程 。
PreparedStatement
接口擴展了Statement
接口,它添加了比Statement
對象更好一些優(yōu)點的功能。
此語句可以動態(tài)地提供/接受參數(shù)。
PreparedStatement pstmt = null;
try {
String SQL = "Update Employees SET age = ? WHERE id = ?";
pstmt = conn.prepareStatement(SQL);
. . .
}
catch (SQLException e) {
. . .
}
finally {
. . .
}
JDBC中的所有參數(shù)都由 ?
符號作為占位符,這被稱為參數(shù)標記。 在執(zhí)行SQL語句之前,必須為每個參數(shù)(占位符)提供值。
setXXX()
方法將值綁定到參數(shù),其中XXX
表示要綁定到輸入?yún)?shù)的值的Java數(shù)據(jù)類型。 如果忘記提供綁定值,則將會拋出一個SQLException
。
每個參數(shù)標記是它其順序位置引用。第一個標記表示位置1
,下一個位置2
等等。 該方法與Java數(shù)組索引不同(它不從0
開始)。
所有Statement
對象與數(shù)據(jù)庫交互的方法(a)execute()
,(b)executeQuery()
和(c)executeUpdate()
也可以用于PreparedStatement
對象。 但是,這些方法被修改為可以使用輸入?yún)?shù)的SQL語句。
就像關(guān)閉Statement
對象一樣,由于同樣的原因(節(jié)省數(shù)據(jù)庫系統(tǒng)資源),也應該關(guān)閉PreparedStatement
對象。
簡單的調(diào)用close()
方法將執(zhí)行關(guān)閉。 如果先關(guān)閉Connection
對象,它也會關(guān)閉PreparedStatement
對象。 但是,應該始終顯式關(guān)閉PreparedStatement
對象,以確保以正確順序清理資源。
PreparedStatement pstmt = null;
try {
String SQL = "Update Employees SET age = ? WHERE id = ?";
pstmt = conn.prepareStatement(SQL);
. . .
}
catch (SQLException e) {
. . .
}
finally {
pstmt.close();
}
為了更好的理解,建議學習PreparedStatement示例代碼 。
類似Connection
對象創(chuàng)建Statement
和PreparedStatement
對象一樣,它還可以使用同樣的方式創(chuàng)建CallableStatement
對象,該對象將用于執(zhí)行對數(shù)據(jù)庫存儲過程的調(diào)用。
假設需要執(zhí)行以下Oracle存儲過程 -
CREATE OR REPLACE PROCEDURE getEmpName
(EMP_ID IN NUMBER, EMP_FIRST OUT VARCHAR) AS
BEGIN
SELECT first INTO EMP_FIRST
FROM Employees
WHERE ID = EMP_ID;
END;
注意:上面的存儲過程是針對Oracle編寫的,但是如果您使用MySQL數(shù)據(jù)庫,可使用以下方式來編寫MySQL相同的存儲過程,如下在EMP數(shù)據(jù)庫中創(chuàng)建它 -
DELIMITER $$
DROP PROCEDURE IF EXISTS `EMP`.`getEmpName` $$
CREATE PROCEDURE `EMP`.`getEmpName`
(IN EMP_ID INT, OUT EMP_FIRST VARCHAR(255))
BEGIN
SELECT first INTO EMP_FIRST
FROM Employees
WHERE ID = EMP_ID;
END $$
DELIMITER ;
存在三種類型的參數(shù):IN
,OUT
和INOUT
。 PreparedStatement
對象只使用IN
參數(shù)。CallableStatement
對象可以使用上面三個參數(shù)類型。
以下是上面三種類型參數(shù)的定義 -
參數(shù) | 描述 |
---|---|
IN | 創(chuàng)建SQL語句時其參數(shù)值是未知的。 使用setXXX() 方法將值綁定到IN 參數(shù)。 |
OUT | 由SQL語句返回的參數(shù)值??梢允褂?code>getXXX()方法從OUT參數(shù)中檢索值。 |
INOUT | 提供輸入和輸出值的參數(shù)。使用setXXX() 方法綁定變量并使用getXXX() 方法檢索值。 |
以下代碼片段顯示了如何使用Connection.prepareCall()
方法根據(jù)上述存儲過程來實例化一個CallableStatement
對象 -
CallableStatement cstmt = null;
try {
String strSQL = "{call getEmpName (?, ?)}";
cstmt = conn.prepareCall (SQL);
. . .
}
catch (SQLException e) {
. . .
}
finally {
. . .
}
String變量strSQL
表示存儲過程,帶有兩個參數(shù)占位符。
使用CallableStatement
對象就像使用PreparedStatement
對象一樣。 在執(zhí)行語句之前,必須將值綁定到所有參數(shù),否則將拋出一個SQLException
異常。
如果有IN
參數(shù),只需遵循適用于PreparedStatement
對象的相同規(guī)則和技術(shù); 使用與綁定的Java數(shù)據(jù)類型相對應的setXXX()
方法。
使用OUT
和INOUT
參數(shù)時,必須使用一個額外的CallableStatement
對象方法registerOutParameter()
。 registerOutParameter()
方法將JDBC數(shù)據(jù)類型綁定到存儲過程并返回預期數(shù)據(jù)類型。
當調(diào)用存儲過程,可以使用適當?shù)?code>getXXX()方法從OUT
參數(shù)中檢索該值。 此方法將檢索到的SQL類型的值轉(zhuǎn)換為對應的Java數(shù)據(jù)類型。
就像關(guān)閉其他Statement
對象一樣,由于同樣的原因(節(jié)省數(shù)據(jù)庫系統(tǒng)資源),還應該關(guān)閉CallableStatement
對象。
簡單的調(diào)用close()
方法將執(zhí)行關(guān)閉CallableStatemen
t對象。 如果先關(guān)閉Connection
對象,它也會關(guān)閉CallableStatement
對象。 但是,應該始終顯式關(guān)閉CallableStatement
對象,以確保按正確順序的清理資源。
CallableStatement cstmt = null;
try {
String SQL = "{call getEmpName (?, ?)}";
cstmt = conn.prepareCall (SQL);
. . .
}
catch (SQLException e) {
. . .
}
finally {
cstmt.close();
}
為了更好的理解,建議參考學習Callable示例代碼。