prepareStatament和Statement和callableStatement的區別

Statement 每次執行sql語句,數據庫都要執行sql語句的編譯 ,最好用於僅執行一次查詢並返回結果的情形,效率高於PreparedStatement.

 

PreparedStatement是預編譯的,使用PreparedStatement有幾個好處

 a. 在執行可變參數的一條SQL時,PreparedStatement比Statement的效率高,因爲DBMS預編譯一條SQL當然會比多次編譯一條SQL的效率要高。

 b. 安全性好,有效防止Sql注入等問題。

 c.  對於多次重複執行的語句,使用PreparedStament效率會更高一點,並且在這種情況下也比較適合使用batch;

 d.  代碼的可讀性和可維護性。

 

CallableStatement接口擴展 PreparedStatement,用來調用存儲過程,它提供了對輸出和輸入/輸出參數的支持。CallableStatement 接口還具有對 PreparedStatement 接口提供的輸入參數的支持。

 

 

 

用法介紹

 

statement 1:

String updateString = "UPDATE COFFEES SET SALES = 75 " + "WHERE COF_NAME LIKE ′Colombian′";
stmt.executeUpdate(updateString);

preparedstatement 2:

PreparedStatement updateSales = con.prepareStatement("UPDATE COFFEES SET SALES = ? WHERE COF_NAME LIKE ? ");
updateSales.setInt(1, 75);
updateSales.setString(2, "Colombian");
updateSales.executeUpdate();

片斷2和片斷1的區別在於,後者使用了PreparedStatement對象,而前者是普通的Statement對象。PreparedStatement對象不僅包含了SQL語句,而且大多數情況下這個語句已經被預編譯過,因而當其執行時,只需DBMS運行SQL語句,而不必先編譯。當你需要執行Statement對象多次的時候,PreparedStatement對象將會大大降低運行時間,當然也加快了訪問數據庫的速度。
這種轉換也給你帶來很大的便利,不必重複SQL語句的句法,而只需更改其中變量的值,便可重新執行SQL語句。選擇PreparedStatement對象與否,在於相同句法的SQL語句是否執行了多次,而且兩次之間的差別僅僅是變量的不同。如果僅僅執行了一次的話,它應該和普通的對象毫無差異,體現不出它預編譯的優越性。
5.執行許多SQL語句的JDBC程序產生大量的Statement和PreparedStatement對象。通常認爲PreparedStatement對象比Statement對象更有效,特別是如果帶有不同參數的同一SQL語句被多次執行的時候。PreparedStatement對象允許數據庫預編譯SQL語句,這樣在隨後的運行中可以節省時間並增加代碼的可讀性。

然而,在Oracle環境中,開發人員實際上有更大的靈活性。當使用Statement或PreparedStatement對象時,Oracle數據庫會緩存SQL語句以便以後使用。在一些情況下,由於驅動器自身需要額外的處理和在Java應用程序和Oracle服務器間增加的網絡活動,執行PreparedStatement對象實際上會花更長的時間。

然而,除了緩衝的問題之外,至少還有一個更好的原因使我們在企業應用程序中更喜歡使用PreparedStatement對象,那就是安全性。傳遞給PreparedStatement對象的參數可以被強制進行類型轉換,使開發人員可以確保在插入或查詢數據時與底層的數據庫格式匹配。

當處理公共Web站點上的用戶傳來的數據的時候,安全性的問題就變得極爲重要。傳遞給PreparedStatement的字符串參數會自動被驅動器忽略。最簡單的情況下,這就意味着當你的程序試着將字符串“D'Angelo”插入到VARCHAR2中時,該語句將不會識別第一個“,”,從而導致悲慘的失敗。幾乎很少有必要創建你自己的字符串忽略代碼。

在Web環境中,有惡意的用戶會利用那些設計不完善的、不能正確處理字符串的應用程序。特別是在公共Web站點上,在沒有首先通過PreparedStatement對象處理的情況下,所有的用戶輸入都不應該傳遞給SQL語句。此外,在用戶有機會修改SQL語句的地方,如HTML的隱藏區域或一個查詢字符串上,SQL語句都不應該被顯示出來。

 

 

 

 

 

callablestatement 使用方法

在 JDBC 中調用已儲存過程的語法如下所示。

{call 過程名[(?, ?, ...)]}


  返回結果參數的過程的語法爲:

{? = call 過程名[(?, ?, ...)]}


  不帶參數的已儲存過程的語法類似:

{call 過程名}


  通常,創建 CallableStatement 對象的人應當知道所用的 DBMS 是支持已儲存過程的,並且知道這些過程都是些什麼。然而,如果需要檢查,多種DatabaseMetaData 方法都可以提供這樣的信息。例如,如果 DBMS 支持已儲存過程的調用,則supportsStoredProcedures 方法將返回 true,而getProcedures 方法將返回對已儲存過程的描述。CallableStatement 繼承 Statement 的方法(它們用於處理一般的 SQL 語句),還繼承了 PreparedStatement 的方法(它們用於處理 IN 參)。

  CallableStatement 中定義的所有方法都用於處理 OUT 參數或 INOUT 參數的輸出部分:註冊 OUT 參數的 JDBC 類型(一般 SQL 類型)、從這些參數中檢索結果,或者檢查所返回的值是否爲 JDBC NULL。

  1、創建 CallableStatement 對象 

  CallableStatement 對象是用 Connection 方法 prepareCall 創建的。下例創建 CallableStatement 的實例,其中含有對已儲存過程 getTestData 調用。該過程有兩個變量,但不含結果參數:

CallableStatement cstmt = con.prepareCall("{call getTestData(?, ?)}");


  其中?佔位符爲IN、OUT還是INOUT參數,取決於已儲存過程getTestData。

  2、IN和OUT參數 

  將IN參數傳給 CallableStatement 對象是通過 setXXX 方法完成的。該方法繼承自 PreparedStatement。所傳入參數的類型決定了所用的setXXX方法(例如,用 setFloat 來傳入 float 值等)。

  如果已儲存過程返回 OUT 參數,則在執行 CallableStatement 對象以前必須先註冊每個 OUT 參數的 JDBC 類型(這是必需的,因爲某些 DBMS 要求 JDBC 類型)。註冊 JDBC 類型是用 registerOutParameter 方法來完成的。語句執行完後,CallableStatement 的 getXXX 方法將取回參數值。正確的 getXXX 方法是爲各參數所註冊的 JDBC 類型所對應的 Java 類型。換言之, registerOutParameter 使用的是 JDBC 類型(因此它與數據庫返回的 JDBC 類型匹配),而 getXXX 將之轉換爲 Java 類型。

  作爲示例,下述代碼先註冊 OUT 參數,執行由 cstmt 所調用的已儲存過程,然後檢索在 OUT 參數中返回的值。方法 getByte 從第一個 OUT 參數中取出一個 Java 字節,而 getBigDecimal 從第二個 OUT 參數中取出一個 BigDecimal 對象(小數點後面帶三位數):

 

CallableStatement cstmt = con.prepareCall("{call getTestData(?, ?)}");
cstmt.registerOutParameter(1, java.sql.Types.TINYINT);
cstmt.registerOutParameter(2, java.sql.Types.DECIMAL, 3);
cstmt.executeQuery();
byte x = cstmt.getByte(1);
java.math.BigDecimal n = cstmt.getBigDecimal(2, 3);

 

3、INOUT參數 

  既支持輸入又接受輸出的參數(INOUT 參數)除了調用 registerOutParameter 方法外,還要求調用適當的 setXXX 方法(該方法是從 PreparedStatement 繼承來的)。setXXX 方法將參數值設置爲輸入參數,而 registerOutParameter 方法將它的 JDBC 類型註冊爲輸出參數。setXXX 方法提供一個 Java 值,而驅動程序先把這個值轉換爲 JDBC 值,然後將它送到數據庫中。這種 IN 值的 JDBC 類型和提供給 registerOutParameter 方法的 JDBC 類型應該相同。然後,要檢索輸出值,就要用對應的 getXXX 方法。例如,Java 類型爲byte 的參數應該使用方法 setByte 來賦輸入值。應該給registerOutParameter 提供類型爲 TINYINT 的 JDBC 類型,同時應使用 getByte 來檢索輸出值。

  下例假設有一個已儲存過程 reviseTotal,其唯一參數是 INOUT 參數。方法setByte 把此參數設爲 25,驅動程序將把它作爲 JDBC TINYINT 類型送到數據庫中。接着,registerOutParameter 將該參數註冊爲 JDBC TINYINT。執行完該已儲存過程後,將返回一個新的 JDBC TINYINT 值。方法 getByte 將把這個新值作爲 Java byte 類型檢索。

CallableStatement cstmt = con.prepareCall("{call reviseTotal(?)}");
cstmt.setByte(1, 25);
cstmt.registerOutParameter(1, java.sql.Types.TINYINT);
cstmt.executeUpdate();
byte x = cstmt.getByte(1);

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章