【Java學習】preparedstatement 處理機制

1. 使用PreparedStatement有什麼樣的優勢?

PreparedStatement是java.sql包下面的一個接口,用來執行SQL語句查詢,通過調用connection.preparedStatement(sql)方法可以獲得PreparedStatment對象。數據庫系統會對sql語句進行預編譯處理(如果JDBC驅動支持的話),預處理語句將被預先編譯好,這條預編譯的sql查詢語句能在將來的查詢中重用,這樣一來,它比Statement對象生成的查詢速度更快。

PreparedStatement提供了諸多好處,企業級應用開發中強烈推薦使用PreparedStatement來做SQL查詢,下面列出PreparedStatement的幾點優勢。

  1. PreparedStatement可以寫動態參數化的查詢
    用PreparedStatement你可以寫帶參數的sql查詢語句,通過使用相同的sql語句和不同的參數值來做查詢比創建一個不同的查詢語句要好,下面是一個參數化查詢:
    1
    SELECT interest_rate FROM loan WHERE loan_type=?
    現在你可以使用任何一種loan類型如:”personal loan”,”home loan” 或者”gold loan”來查詢,這個例子叫做參數化查詢,因爲它可以用不同的參數調用它,這裏的”?”就是參數的佔位符。
  2. PreparedStatementStatement 更快
    使用 PreparedStatement 最重要的一點好處是它擁有更佳的性能優勢,SQL語句會預編譯在數據庫系統中。執行計劃同樣會被緩存起來,它允許數據庫做參數化查詢。使用預處理語句比普通的查詢更快,因爲它做的工作更少(數據庫對SQL語句的分析,編譯,優化已經在第一次查詢前完成了)。爲了減少數據庫的負載,生產環境中德JDBC代碼你應該總是使用PreparedStatement 。值得注意的一點是:爲了獲得性能上的優勢,應該使用參數化sql查詢而不是字符串追加的方式。

 

2. PreparedStatement如何防止SQL注入的?

  1. 如果你是做Java web應用開發的,那麼必須熟悉那聲名狼藉的SQL注入式攻擊。去年Sony就遭受了SQL注入攻擊,被盜用了一些Sony play station(PS機)用戶的數據。在SQL注入攻擊裏,惡意用戶通過SQL元數據綁定輸入,比如:某個網站的登錄驗證SQL查詢代碼爲:
    strSQL = "SELECT * FROM users WHERE name = '" + userName + "' and pw = '"+ passWord +"';"

    惡意填入:

    userName = "1' OR '1'='1";
    passWord = "1' OR '1'='1";

    那麼最終SQL語句變成了:

    strSQL = "SELECT * FROM users WHERE name = '1' OR '1'='1' and pw = '1' OR '1'='1';"

    因爲WHERE條件恆爲真,這就相當於執行:

    strSQL = "SELECT * FROM users;"

    因此可以達到無賬號密碼亦可登錄網站。如果惡意用戶要是更壞一點,用戶填入:
strSQL = "SELECT * FROM users WHERE name = 'any_value' and 
pw = ''; DROP TABLE users"

  1. 這樣一來,雖然沒有登錄,但是數據表都被刪除了。
    然而使用PreparedStatement的參數化的查詢可以阻止大部分的SQL注入。在使用參數化查詢的情況下,數據庫系統(eg:MySQL)不會將參數的內容視爲SQL指令的一部分來處理,而是在數據庫完成SQL指令的編譯後,才套用參數運行,因此就算參數中含有破壞性的指令,也不會被數據庫所運行。
  2. PreparedStatement的侷限性

    儘管PreparedStatement非常實用,但是它仍有一定的限制。
    1. 爲了防止SQL注入攻擊,PreparedStatement不允許一個佔位符(?)有多個值,在執行有**IN**子句查詢的時候這個問題變得棘手起來。下面這個SQL查詢使用PreparedStatement就不會返回任何結果

     

    SELECT * FROM loan WHERE loan_type IN (?)
    preparedSatement.setString(1, "'personal loan', 'home loan', 'gold loan'");

     

3.關於PreparedStatement的總結

1. PreparedStatement可以寫參數化查詢,比Statement能獲得更好的性能。

2. 對於PreparedStatement來說,數據庫可以使用已經編譯過及定義好的執行計劃,這種預處理語句查詢比普通的查詢運行速度更快。

3. PreparedStatement可以阻止常見的SQL注入式攻擊。

4. PreparedStatement可以寫動態查詢語句

5. PreparedStatement與java.sql.Connection對象是關聯的,一旦你關閉了connection,PreparedStatement也沒法使用了。

6. “?” 叫做佔位符。

7. PreparedStatement查詢默認返回FORWARD_ONLY的ResultSet,你只能往一個方向移動結果集的遊標。當然你還可以設定爲其他類型的值如:”CONCUR_READ_ONLY”。

8. 不支持預編譯SQL查詢的JDBC驅動,在調用connection.prepareStatement(sql)的時候,它不會把SQL查詢語句發送給數據庫做預處理,而是等到執行查詢動作的時候(調用executeQuery()方法時)才把查詢語句發送個數據庫,這種情況和使用Statement是一樣的。

9. 佔位符的索引位置從1開始而不是0,如果填入0會導致*java.sql.SQLException invalid column index*異常。所以如果PreparedStatement有兩個佔位符,那麼第一個參數的索引時1,第二個參數的索引是2.

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