- 輕量級Java EE企業應用開發實戰
- 柳偉衛編著
- 1056字
- 2022-07-29 14:31:26
5.3 使用PreparedStatement
PreparedStatement接口擴展了Statement,添加了為語句中包含的參數標記設置值的功能。
PreparedStatement對象表示已經預編譯的SQL語句,這樣SQL語句只需要編譯一次就可以被執行多次。參數標記(由SQL字符串中的“?”表示)用于指定語句的輸入值,這些值可能在運行時發生變化。
5.3.1 創建PreparedStatement對象
PreparedStatement的實例以與Statement對象相同的方式創建,除了在創建語句時提供SQL命令:
Connection conn = ds.getConnection(user, passwd); PreparedStatement ps = conn.prepareStatement("INSERT INTO BOOKLIST" + "(AUTHOR, TITLE, ISBN) VALUES (?, ?, ?)");
與createStatement一樣,方法prepareStatement定義了一個構造函數,該構造函數可用于指定由該PreparedStatement生成的結果集的特征。
Connection conn = ds.getConnection(user, passwd); PreparedStatement ps = conn.prepareStatement( "SELECT AUTHOR, TITLE FROM BOOKLIST WHERE ISBN = ?", ResultSet.TYPE_FORWARD_ONLY, ResultSet.CONCUR_UPDATABLE);
PreparedStatement接口定義setter方法,這些方法用于替換預編譯SQL字符串中每個參數標記的值。方法的名稱遵循set模式。
例如,方法setString用于指定期望字符串的參數標記的值。這些setter方法中的每一個至少采用兩個參數:第一個始終是一個Int值,等于要設置的參數的序號位置從1開始;第二個和任何剩余參數指定要分配給參數的值。
PreparedStatement ps = conn.prepareStatement("INSERT INTO BOOKLIST" + "(AUTHOR, TITLE, ISBN) VALUES (?, ?, ?)"); ps.setString(1, "Way, Lau"); ps.setString(2, "We"); ps.setLong(3, 140185852L);
必須為PreparedStatement對象中的每個參數標記提供一個值,然后才能執行它。如果沒有為參數標記提供值,那么用于執行PreparedStatement對象(executeQuery、executeUpdate和execute)的方法將拋出SQLException。
為PreparedStatement對象的參數標記設置的值在執行時不會重置,可以調用clearParameters方法來顯式清除已設置的值。使用不同的值設置參數將使用新值替換先前的值。
5.3.2 為什么使用PreparedStatement
建議開發者始終以PreparedStatement代替Statement,換言之,在任何時候都不要直接使用Statement。PreparedStatement具有以下優勢:
1.提升代碼的可讀性和可維護性
雖然用PreparedStatement代替Statement會使代碼多出幾行,但這樣的代碼無論從可讀性還是可維護性上來說都比直接用Statement的代碼檔次高。
2.提高性能
PreparedStatement實例包含已編譯的SQL語句,這就是使語句“準備好”。包含于PreparedStatement對象中的SQL語句可具有一個或多個IN參數。IN參數的值在SQL語句創建時未被指定。相反,該語句為每個IN參數保留一個問號(?)作為參數標記。每個問號的值必須在該語句執行之前通過適當的set方法來提供。由于PreparedStatement對象已預編譯過,其執行速度要快于Statement對象,因此多次執行的SQL語句經常創建為PreparedStatement對象以提高效率。
3.提高安全性
即使到目前為止,仍有一些人連基本的SQL語法都不知道,比如下面的例子:
String sql ="select * from tb_name where name= '" + varname+"' and passwd='"+ varpasswd+"'";
如果我們把“' or '1' = '1”作為varpasswd傳入進來,用戶名隨意,則最終語句如下:
select*from tb_name ='t_user'and passwd =''or'1'='1';
因為'1'='1'肯定成立,所以這個語句肯定能通過驗證,而不管用戶名和密碼是否合法。更有甚者把“;drop table tb_name;”作為varpasswd傳入進來,SQL語句將變成:
select*from tb_name ='t_user'and passwd ='';droptable tb_name;
上面就是SQL注入的例子。
而如果使用PreparedStatement,那么傳入的任何內容都不會和原來的語句發生任何匹配的關系。只要全部使用PreparedStatement語句,就不用對傳入的數據做任何過濾。而如果使用普通的Statement,就需要額外做很多防SQL注入的工作。