轉載請注明原文地址: http://www.cnblogs.com/ygj0930/p/5876951.html
在JDBC編程中,常用Statement、PreparedStatement 和 CallableStatement三種方式來執行查詢語句,其中 Statement 用於通用查詢, PreparedStatement 用於執行參數化查詢,而 CallableStatement則是用於存儲過程。
1、Statement
該對象用於執行靜態的 SQL 語句,並且返回執行結果。 此處的SQL語句必須是完整的,有明確的數據指示。查的是哪條記錄?改的是哪條記錄?都要指示清楚。
通過調用 Connection 對象的 createStatement 方法創建該對象
查詢:ResultSet excuteQuery(String sql)——返回查詢結果的封裝對象ResultSet. 用next()遍歷結果集,getXX()獲取記錄數據。
修改、刪除、增加:int excuteUpdate(String sql)——返回影響的數據表記錄數.
2、PreparedStatement
SQL 語句被預編譯並存儲在 PreparedStatement 對象中。然后可以使用此對象多次高效地執行該語句。
可以通過調用 Connection 對象的 preparedStatement() 方法獲取 PreparedStatement 對象
PreparedStatement 對象所執行的 SQL 語句中,參數用問號(?)來表示,調用 PreparedStatement 對象的 setXXX() 方法來設置這些參數. setXXX() 方法有兩個參數,第一個參數是要設置的 SQL 語句中的參數的索引(從 1 開始),第二個是設置的 SQL 語句中的參數的值,注意用setXXX方式設置時,需要與數據庫中的字段類型對應,例如mysql中字段為varchar,就需要使用setString方法,如果為Date類型,就需要使用setDate方法來設置具體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