轉載請註明原文地址: http://www.cnblogs.com/ygj0930/p/5876951.htmlhtml
在JDBC編程中,經常使用Statement、PreparedStatement 和 CallableStatement三種方式來執行查詢語句,其中 Statement 用於通用查詢, PreparedStatement 用於執行參數化查詢,而 CallableStatement則是用於存儲過程。java
一、Statement
該對象用於執行靜態的 SQL 語句,而且返回執行結果。 此處的SQL語句必須是完整的,有明確的數據指示。查的是哪條記錄?改的是哪條記錄?都要指示清楚。
經過調用 Connection 對象的 createStatement 方法建立該對象
查詢:ResultSet excuteQuery(String sql)——返回查詢結果的封裝對象ResultSet. 用next()遍歷結果集,getXX()獲取記錄數據。
修改、刪除、增長:int excuteUpdate(String sql)——返回影響的數據表記錄數. mysql
二、PreparedStatement
SQL 語句被預編譯並存儲在 PreparedStatement 對象中。而後可使用此對象屢次高效地執行該語句。
能夠經過調用 Connection 對象的 preparedStatement() 方法獲取 PreparedStatement 對象
PreparedStatement 對象所執行的 SQL 語句中,參數用問號(?)來表示,調用 PreparedStatement 對象的 setXXX() 方法來設置這些參數. setXXX() 方法有兩個參數,第一個參數是要設置的 SQL 語句中的參數的索引(從 1 開始),第二個是設置的 SQL 語句中的參數的值,注意用setXXX方式設置時,須要與數據庫中的字段類型對應,例如mysql中字段爲varchar,就須要使用setString方法,若是爲Date類型,就須要使用setDate方法來設置具體sql的參數。sql
簡單來講就是,預編譯的SQL語句不是有具體數值的語句,而是用(?)來代替具體數據,而後在執行的時候再調用setXX()方法把具體的數據傳入。同時,這個語句只在第一次執行的時候編譯一次,而後保存在緩存中。以後執行時,只需從緩存中抽取編譯過了的代碼以及新傳進來的具體數據,便可得到完整的sql命令。這樣一來就省下了後面每次執行時語句的編譯時間。數據庫
使用預編譯分4步走:編程
1:定義預編譯的sql語句,其中待填入的參數用 ? 佔位。注意,?無關類型,不須要加分號之類。其具體數據類型在下面setXX()時決定。緩存
2:建立預編譯Statement,並把sql語句傳入。此時sql語句已與此preparedStatement綁定。因此第4步執行語句時無需再把sql語句做爲參數傳入execute()。性能
3:填入具體參數。經過setXX(問號下標,數值)來爲sql語句填入具體數據。注意:問號下標從1開始,setXX與數值類型有關,字符串就是setString(index,str).優化
4:執行預處理對象。主要有:網站
boolean |
execute() 在此 PreparedStatement 對象中執行 SQL 語句,該語句能夠是任何種類的 SQL 語句。 |
ResultSet |
executeQuery() 在此 PreparedStatement 對象中執行 SQL 查詢,並返回該查詢生成的 ResultSet 對象。 |
int |
executeUpdate() 在此 PreparedStatement 對象中執行 SQL 語句,該語句必須是一個 SQL 數據操做語言(Data Manipulation Language,DML)語句,好比 INSERT 、UPDATE 或 DELETE 語句;或者是無返回內容的 SQL 語句,好比 DDL 語句。 |
注意,前面建立preparedstatement時已經把sql語句傳入了,此時執行不需再把sql語句傳入,這是與通常statement執行sql語句所不一樣之處。
好比:
String sql="select Sname from stu where Sno=?"
PreparedStatement prestmt = conn.prepareStatement(sql
);
prestmt.setString(
1
,sno);
prestmt.executeQuery();
使用預編譯的好處:
1:PreparedStatement比 Statement 更快
使用 PreparedStatement 最重要的一點好處是它擁有更佳的性能優點,SQL語句會預編譯在數據庫系統中。執行計劃一樣會被緩存起來,它容許數據庫作參數化查詢。使用預處理語句比普通的查詢更快,由於它作的工做更少(數據庫對SQL語句的分析,編譯,優化已經在第一次查詢前完成了)。
2:PreparedStatement能夠防止SQL注入式攻擊
SQL 注入攻擊:SQL 注入是利用某些系統沒有對用戶輸入的數據進行充分的檢查,而在用戶輸入數據中注入非法的 SQL 語句段或命令,從而利用系統的 SQL 引擎完成惡意行爲的作法。
好比:某個網站的登陸驗證SQL查詢代碼爲:
1
|
strSQL =
"SELECT * FROM users WHERE name = '"
+ userName +
"' and pw = '"
+ passWord +
"';"
|
惡意填入:
1
2
|
userName =
"1' OR '1'='1"
;
passWord =
"1' OR '1'='1"
;
|
那麼最終SQL語句變成了:
1
|
strSQL =
"SELECT * FROM users WHERE name = '1' OR '1'='1' and pw = '1' OR '1'='1';"
|
由於WHERE條件恆爲真,這就至關於執行:
1
|
strSQL =
"SELECT * FROM users;"
|
所以能夠達到無帳號密碼亦可登陸網站。
若是惡意用戶要是更壞一點,SQL語句變成:
1
|
strSQL =
"SELECT * FROM users WHERE name = 'any_value' and pw = ''; DROP TABLE users"
|
這樣一來,雖然沒有登陸,可是數據表都被刪除了。
使用PreparedStatement的參數化的查詢能夠阻止大部分的SQL注入。在使用參數化查詢的狀況下,數據庫系統不會將參數的內容視爲SQL指令的一部分來處理,而是在數據庫完成SQL指令的編譯後,才套用參數運行,所以就算參數中含有破壞性的指令,也不會被數據庫所運行。由於對於參數化查詢來講,查詢SQL語句的格式是已經規定好了的,須要查的數據也設置好了,缺的只是具體的那幾個數據而已。因此用戶能提供的只是數據,並且只能按需提供,沒法更進一步作出影響數據庫的其餘舉動來。
參考資料:
http://www.importnew.com/5006.html