PrepareStatement與Statement之間的區別

edagarli發表於2014-03-16

  1. preparestatement是預編譯,對於批量處理可以大大提高執行效率。
  2. 如果說所使用的SQL語句是一次性的話,那麼使用statement較好,因為,這樣的話使用preparestatement並不會產生太大的效果,相反,可能還會在效能方面劣於statement。畢竟preparestatement物件開銷比statement較大。
  3. statement每次執行sql 語句,相關資料庫都要對sql語句進行編譯,而preparestatement則不需要。
  4. 執行許多SQL語句的JDBC程式產生大量的Statement和PreparedStatement物件。通常認為PreparedStatement物件比Statement物件更有效,特別是如果帶有不同引數的同一SQL語句被多次執行的時候。PreparedStatement物件允許資料庫預編譯SQL語句,這樣在隨後的執行中可以節省時間並增加程式碼的可讀性。
  5. 在企業應用程式中更喜歡使用PreparedStatement物件是因為它還具有安全性。傳遞給PreparedStatement物件的引數可以被強制進行型別轉換,使開發人員可以確保在插入或查詢資料時與底層的資料庫格式匹配。為什麼我們比較常用PrepareStatement,有位高手跟我們講述了許多,下面我將把它拷貝下來,與大家一同分享:
  6. 一.程式碼的可讀性和可維護性. 
    雖然用PreparedStatement來代替Statement會使程式碼多出幾行,但這樣的程式碼無論從可讀性還是可維護性上來說.都比直接用Statement的程式碼高很多檔次: 

    stmt.executeUpdate( "insert   into   tb_name   (col1,col2,col2,col4)   values   ( ' "+var1+ " ', ' "+var2+ " ', "+var3+ ", ' "+var4+ " ') "); 

    perstmt   =   con.prepareStatement( "insert   into   tb_name   (col1,col2,col2,col4)   values   (?,?,?,?) "); 
    perstmt.setString(1,var1); 
    perstmt.setString(2,var2); 
    perstmt.setString(3,var3); 
    perstmt.setString(4,var4); 
    perstmt.executeUpdate(); 

    不用我多說,對於第一種方法.別說其他人去讀你的程式碼,就是你自己過一段時間再去讀,都會覺得傷心. 

    二.PreparedStatement盡最大可能提高效能(特別是批量處理時). 
    每一種資料庫都會盡最大努力對預編譯語句提供最大的效能優化.因為預編譯語句有可能被重複呼叫.所以語句在被DB的編譯器編譯後的執行程式碼被快取下來,那麼下次呼叫時只要是相同的預編譯語句就不需要編譯,只要將引數直接傳入編譯過的語句執行程式碼中(相當於一個涵數)就會得到執行.這並不是說只有一個Connection中多次執行的預編譯語句被快取,而是對於整個DB中,只要預編譯的語句語法和快取中匹配.那麼在任何時候就可以不需要再次編譯而可以直接執行.而statement的語句中,即使是相同一操作,而由於每次操作的資料不同所以使整個語句相匹配的機會極小,幾乎不太可能匹配.比如: 
    insert   into   tb_name   (col1,col2)   values   ( '11 ', '22 '); 
    insert   into   tb_name   (col1,col2)   values   ( '11 ', '23 '); 
    即使是相同操作但因為資料內容不一樣,所以整個個語句本身不能匹配,沒有快取語句的意義.事實是沒有資料庫會對普通語句編譯後的執行程式碼快取.這樣每執行一次都要對傳入的語句編譯一次. 

    當然並不是所以預編譯語句都一定會被快取,資料庫本身會用一種策略,比如使用頻度等因素來決定什麼時候不再快取已有的預編譯結果.以儲存有更多的空間儲存新的預編譯語句. 

    三.最重要的一點是極大地提高了安全性. 

    即使到目前為止,仍有一些人連基本的惡義SQL語法都不知道. 
    String   sql   =   "select   *   from   tb_name   where   name=   ' "+varname+ " '   and   passwd= ' "+varpasswd+ " ' "; 
    如果我們把[ '   or   '1 '   =   '1]作為varpasswd傳入進來.使用者名稱隨意,看看會成為什麼? 

    select   *   from   tb_name   =   '隨意 '   and   passwd   =   ' '   or   '1 '   =   '1 '; 
    因為 '1 '= '1 '肯定成立,所以可以任何通過驗證.更有甚者: 
    把[ ';drop   table   tb_name;]作為varpasswd傳入進來,則: 
    select   *   from   tb_name   =   '隨意 '   and   passwd   =   ' ';drop   table   tb_name;有些資料庫是不會讓你成功的,但也有很多資料庫就可以使這些語句得到執行. 

    而如果你使用預編譯語句.你傳入的任何內容就不會和原來的語句發生任何匹配的關係.(前提是資料庫本身支援預編譯,但上前可能沒有什麼服務端資料庫不支援編譯了,只有少數的桌面資料庫,就是直接檔案訪問的那些)只要全使用預編譯語句,你就用不著對傳入的資料做任何過慮.而如果使用普通的statement,有可能要對drop,;等做費盡心機的判斷和過慮. 


相關文章