2010-07-17 38 views
177

準備報表是一個稍微更強大的報表版本,並且至少應該像報表一樣快速且容易地處理。
準備好的語句可參數化報表與準備報表之間的區別

大多數關係型數據庫負責處理四個步驟JDBC/SQL查詢:

  1. 解析傳入的SQL查詢
  2. 編譯SQL查詢
  3. 規劃/優化數據採集​​路徑
  4. 執行優化查詢/獲取並返回數據

對於發送到數據庫的每個SQL查詢,語句將始終通過上述四個步驟進行。準備好的陳述預先執行上述執行過程中的步驟(1) - (3)。因此,在創建預備聲明時,會立即執行一些預優化。其效果是在執行時減少數據庫引擎的負載。

現在我的問題是 - 「使用Prepared Statement的其他好處是什麼?」

+8

根據我的說法,最有效的一個是您的查詢可以動態參數化 – 2012-11-02 09:45:57

回答

32

PreparedStatement在防止SQL injection attacks是一個非常好的防守(但不是萬無一失)。綁定參數值是防止"little Bobby Tables"進行不必要的訪問的好方法。

+5

如何通過預處理語句執行SQL注入? – 2010-07-17 12:17:24

+1

Michael, 作爲參數傳遞給準備語句的變量將自動由JDBC驅動程序轉義。 – 2010-07-17 19:09:21

+2

您可以舉一個SQL注入攻擊如何對準備語句的例子嗎?你是否在數據庫代碼中出現錯誤? – 2010-07-17 22:50:41

10

沒有太多的補充,

1 - 如果你想執行一個循環(超過1次)查詢,備言可能是因爲你提到的優化的速度更快。

2-參數化查詢是避免SQL注入的一種好方法,它只在PreparedStatement中可用。

155

一個PreparedStatement的優點:SQL語句的

  • 預編譯和DB端緩存導致總體更快的執行速度和重複使用相同的SQL語句batches的能力。

  • SQL injectionattacks通過內置轉義引號和其他特殊字符自動阻止。注意,這需要你使用任何的PreparedStatementsetXxx()方法來設置值

    preparedStatement = connection.prepareStatement("INSERT INTO Person (name, email, birthdate, photo) VALUES (?, ?, ?, ?)"); 
    preparedStatement.setString(1, person.getName()); 
    preparedStatement.setString(2, person.getEmail()); 
    preparedStatement.setTimestamp(3, new Timestamp(person.getBirthdate().getTime())); 
    preparedStatement.setBinaryStream(4, person.getPhoto()); 
    preparedStatement.executeUpdate(); 
    

    ,因此通過字符串串接不內嵌在SQL字符串的值。

    preparedStatement = connection.prepareStatement("INSERT INTO Person (name, email) VALUES ('" + person.getName() + "', '" + person.getEmail() + "'"); 
    preparedStatement.executeUpdate(); 
    
  • 簡化SQL字符串中非標準Java對象的設置,例如, Date, Time, Timestamp, BigDecimal, InputStreamBlob)和ReaderClob)。在大多數這些類型中,您不能像在簡單的Statement中那樣「僅」執行toString()。你甚至可以把它所有的重構使用PreparedStatement#setObject()循環內部,如下實用方法證明:

    public static void setValues(PreparedStatement preparedStatement, Object... values) throws SQLException { 
        for (int i = 0; i < values.length; i++) { 
         preparedStatement.setObject(i + 1, values[i]); 
        } 
    } 
    

    因而可作如下:

    preparedStatement = connection.prepareStatement("INSERT INTO Person (name, email, birthdate, photo) VALUES (?, ?, ?, ?)"); 
    setValues(preparedStatement, person.getName(), person.getEmail(), new Timestamp(person.getBirthdate().getTime()), person.getPhoto()); 
    preparedStatement.executeUpdate(); 
    
+3

一個描述性和解釋性文本,加上參考文獻和例子,是一個很好的答案。 +1 – XenoRo 2012-11-05 12:58:55

+0

糾正我,如果我錯了,但沒有條件檢索數據的查詢最好用正則語句。即: 'SELECT * FROM user_activity;' – 2014-07-03 19:21:47

+0

@ R.D。這可能是事實,因爲準備好的聲明需要2次往返數據庫:第一次準備,第二次執行。但是,我會測試它。我認爲該計劃仍然會被緩存在數據庫服務器中用於「陳述」,但它可能值得一試。 – Brandon 2014-10-15 15:59:02

5

不能做的CLOB一份聲明。

和:(OraclePreparedStatement)PS

2
  • 它更容易閱讀
  • 您可以輕鬆地查詢字符串常量
2

SQL注入是通過準備好的聲明中忽略,以便安全是增加準備語句

1

Statement接口執行無參數的靜態SQL語句

PreparedStatement接口(擴展聲明)執行預編譯SQL語句帶/不帶參數

  1. 高效的重複執行

  2. 它是預編譯因此它的速度更快

38
  1. 它們是預編譯的(一次),因此可以更快地重複執行動態SQL(w這裏參數的變化)

  2. 數據庫語句緩存提升DB執行性能

    的先前執行計劃數據庫存儲高速緩存執行的語句。這允許數據庫引擎重複使用先前執行的語句的計劃。因爲PreparedStatement使用參數,所以每次執行時都會顯示爲相同的SQL,數據庫可以重用先前的訪問計劃,從而減少處理。語句將參數「內聯」到SQL字符串中,因此不會與數據庫顯示爲相同的SQL,從而防止緩存使用。

  3. 二進制通信協議意味着更少的帶寬,更快的通訊科調用DB服務器

    準備語句通常通過非SQL二進制協議執行。這意味着數據包中的數據較少,因此與服務器的通信速度更快。根據經驗,網絡操作比磁盤操作快一個數量級,比內存CPU操作快一個數量級。因此,通過網絡發送的任何數據量的減少都會對整體性能產生很好的影響。

  4. 它們通過爲所提供的所有參數值轉義文本來防止SQL注入。

  5. 它們提供了查詢代碼和參數值(與連接的SQL字符串相比)之間更強的分離,提高了可讀性並幫助代碼維護人員快速理解查詢的輸入和輸出。

  6. 在java中,可以分別

  7. 調用的getMetaData()和getParameterMetadata(),以反映對結果集的字段和參數字段,在java中,智能地接受java對象作爲經由的setObject,setBoolean參數類型, setByte,setDate,setDouble,setDouble,setFloat,setInt,setLong,setShort,setTime,setTimestamp - 它轉換爲DB類型的格式(不僅僅是toString()格式)。

  8. 在java中,接受SQL陣列,經由setArray方法參數類型

  9. 在java中,接受的CLOB,BLOB的,OutputStreams與讀者作爲參數通過的setClob/setNClob,的setBlob,的setBinaryStream,的setCharacterStream/「進料」 DB-特定調用setAsciiStream/setNCharacterStream方法,分別

  10. 在java中,允許值,爲SQL數據鏈,SQL ROWID,SQL XML和NULL經由setURL,setRowId,setSQLXML ANS的setNull方法設定

  11. 在java中,繼承了一個來自Statement的所有方法。它繼承了addBatch方法,並且還允許添加一組參數值,以通過addBatch方法匹配批處理的SQL命令集。

  12. 在java中,特殊類型的PreparedStatement(子類CallableStatement)允許執行存儲過程 - 支持高性能,封裝,過程編程和SQL,DB管理/維護/調整邏輯以及使用專有數據庫邏輯&功能

+0

當所有這些奇蹟都是隻有界面的時候,它們都是可能的嗎?!?! – Rafael 2014-04-05 11:52:01

+1

'奇蹟'是通過標準工廠方法實現的,這些方法返回(供應商特定的)接口實現:'Connection.createStatement'和'Connection.prepareStatement'。這種設計迫使你對接口工作,所以你不需要知道具體的實現類,並避免與這種實現類的不必要的緊耦合。所有這些都通過Java jdbc文檔和Java文檔中的示例進行了解釋。 :) – 2014-04-08 11:36:15

2

語句將用於執行靜態SQL語句,它不能接受輸入參數。

PreparedStatement將用於多次動態執行SQL語句。它將接受輸入參數。

7

陳述是靜態的,準備陳述是動態的。

聲明適用於DDL併爲DML準備了聲明。

語句速度較慢,而準備語句更快。

more differences

20

一些PreparedStatement的過聲明的好處是:

  1. 的PreparedStatement幫助我們防止SQL注入攻擊,因爲它會自動轉義特殊字符。
  2. PreparedStatement允許我們執行帶有參數輸入的動態查詢。
  3. PreparedStatement提供了不同類型的setter方法來設置查詢的輸入參數。
  4. PreparedStatement比Statement快。當我們重新使用PreparedStatement或使用批處理方法執行多個查詢時,它變得更加明顯。
  5. PreparedStatement幫助我們用setter方法編寫面向對象的代碼,而使用Statement我們必須使用String Concatenation來創建查詢。如果要設置多個參數,那麼使用字符串連接編寫查詢看起來非常難看且容易出錯。

閱讀在http://www.journaldev.com/2489/jdbc-statement-vs-preparedstatement-sql-injection-example

0

不明白的困惑更多關於SQL注入的問題:只需記住

  1. 聲明用於類的DDL靜態查詢即創建,刪除,修改和prepareStatement用於動態查詢即DML查詢。
  2. 在聲明中,查詢未預編譯,而prepareStatement查詢是預編譯的,因爲prepareStatement是省時的。
  3. prepareStatement在創建時需要參數,而Statement不帶參數。 例如,如果要創建表並插入元素,則:: 使用Statement和Insert元素(動態)通過使用prepareStatement創建表(靜態)。
+0

prepareStatement在創建時需要參數,而Statement不帶參數。 – 2015-06-01 11:17:24

2
準備

或參數化查詢的另一特徵:Reference taken from this article.

這種說法是在其中相同的SQL語句以高效率反覆執行數據庫系統的特徵之一。預先準備好的語句是一種模板,由具有不同參數的應用程序使用。

語句模板被準備併發送到數據庫系統和數據庫系統執行該模板的解析,編譯和優化,並在不執行的情況下進行存儲。

某些參數如where子句在模板創建後期應用程序時不傳遞,將這些參數發送到SQL語句的數據庫系統和數據庫系統使用模板,並根據請求執行。

準備好的語句對SQL注入非常有用,因爲應用程序可以使用不同的技術和協議來準備參數。

當數據數量增加並且索引頻繁更改時,Prepared Statements可能會失敗,因爲在這種情況下需要新的查詢計劃。

2

引述由mattjames

的用途,JDBC一個聲明應爲100%定位於正在使用 對於DDL(ALTER,CREATE,GRANT等),因爲這些是僅有的語句 類型的不能接受BIND VARIABLES。 PreparedStatements或 CallableStatements應該用於每種其他類型的語句 (DML,查詢)。因爲這些是接受綁定 變量的語句類型。

這是一個事實,一個規則,一個法律 - 使用準備好的聲明無處不在。 使用STATEMENTS幾乎沒有地方。