Statement和PreparedStatement之間的區別

在drp視頻中,老師在數據庫執行sql語句的時候多使用的是PreparedStatment,但是也提到了Statement。在視頻中提到了一些區別,但是覺得不是很詳細。

  視頻中提到PreparedStatement的優點包括兩個:

   1)會儘可能的提高性能

   2)提高安全性(防止SQL Injeciton)

  二者相差一個單詞Prepared,prepared的意思是準備好的。在處理SQL語句的時候PreparedStatement用於處理動態SQL語句,在執行前會有一個預編譯過程,它是有時間開銷的,雖然相對數據庫的操作該時間開銷可以忽略不計,但是Preparedstatement的預編譯結果會被緩存,下次執行相同的sql語句是,數據庫端不會再進行編譯了。而直接用數據庫的緩衝區,提高數據訪問率。

一、在編寫代碼過程:

 Statement:

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

   PreparedStatement:
          pstmt = con.prepareStatement("insert into tb_name(col1,col2,col2,col4) values (?,?,?,?)");     pstmt.setString(1,var1);     pstmt.setString(2,var2);     pstmt.setString(3,var3);     pstmt.setString(4,var4);     pstmt.executeUpdate();
   可以看出來statement的代碼寫起來比較少但是給人的感覺就是亂,而且還容易出錯;但是preparedStatement的代碼雖然長一點,但是直接一個.就可以敲出來,給人的感覺是簡單而且不容易出錯。
   二、在性能方面:
   如果是大型的軟件,需要保存在數據庫中的數據量是非常大的,那麼就要涉及到性能問題,無論是oracle還是SQL server都是這樣的,每一種數據庫都會近最大的努力對預編譯語句提供最大的性能優化,因爲有些編譯語句有可能被重複調用。所以就有把被數據庫編譯後的執行代碼緩存起來,當下次調用只要是相同的預編譯語句就不需要編譯。只要將參數直接傳入編譯過的語句執行代碼中(相當於一個涵數)就會得到執行.這並不是說只有一個Connection中多次執行的預編譯語句被緩存,而是對於整個DB中,只要預編譯的語句語法和緩存中匹配.那麼在任何時候就可以不需要再次編譯而可以直接執行.而statement的語句中,即使是相同一操作,而由於每次操作的數據不同所以使整個語句相匹配的機會極小,幾乎不太可能匹配.比如:
    insert into tb_name (col1,col2) values ('11','22');
    insert into tb_name (col1,col2) values ('11','23');
    即使是相同操作但因爲數據內容不一樣,所以整個個語句本身不能匹配,沒有緩存語句的意義.事實是沒有數據庫會對普通語句編譯後的執行代碼緩存.
當然並不是所以預編譯語句都一定會被緩存,數據庫本身會用一種策略,比如使用頻度等因素來決定什麼時候不再緩存已有的預編譯結果.以保存有更多的空間存儲新的預編譯語句.這樣能保持一種內存空間的平衡,不至於因爲有過多的緩存而崩潰。
  三、安全性
  安全性是軟件中最重要的一個問題,如果你的軟件存在安全性問題那麼你的軟件也就無人問津了。而preparedStatement和statement就存在這樣的問題。 
   在視頻中講解了一下sql注入的問題。  
    String sql = "select * from tb_name where name= '"+varname+"' and passwd='"+varpasswd+"'";
    如果我們把[' or '1' = '1]作爲varpasswd傳入進來.用戶名hzy,看看會成爲什麼?
    select * from tb_name = 'hzy' and passwd = '' or '1' = '1';
    因爲'1'='1'肯定成立,所以可以任何通過驗證.更有甚者:
把drop table tb_name;]作爲varpasswd傳入進來,則:
select * from tb_name = '隨意' and passwd = '';drop table tb_name;有些數據庫是不會讓你成功的,但也有很多數據庫就可以使這些語句得到執行.
而如果你使用預編譯語句.你傳入的任何內容就不會和原來的語句發生任何匹配的關係.只要全使用預編譯語句,你就用不着對傳入的數據做任何過慮.而如果使用普通的statement,有可能要對drop,;等做費盡心機的判斷和過慮.
  PreparedStatement繼承於Statement,通常的JDBC實現中PreparedStatement最終還是通過Statement的相關方法來執行SQL的(可以做少量優化),其最主要的優勢在於,可以減少SQL的編譯錯誤(在JDBC中就可以捕獲部分異常而不是由數據庫服務器執行時返回錯誤代碼)、增加SQL安全性(減少SQL注入的機會)
    把PreparedStatement說的如此之好,並不是說statement就沒有存在的意義了,對於不重複使用和可以控制輸入值的情況下statement在性能上還是比較好的。每個東西都有它存在的必然道理,對與解決的問題的辦法沒有絕對的好也沒有絕對的不好。

原文出處:http://hanzhengyang0126.blog.163.com/blog/static/117503945201111294828507/
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章