官术网_书友最值得收藏!

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注入的工作。

主站蜘蛛池模板: 吐鲁番市| 亳州市| 建昌县| 阿图什市| 莎车县| 白朗县| 洛隆县| 波密县| 阳朔县| 肇东市| 山西省| 岳普湖县| 扶沟县| 绥滨县| 建始县| 克拉玛依市| 古蔺县| 读书| 阳西县| 稷山县| 苍山县| 安塞县| 苏尼特左旗| 璧山县| 柘荣县| 元谋县| 南康市| 田林县| 贵港市| 左云县| SHOW| 辽宁省| 虹口区| 五原县| 塘沽区| 浦北县| 扬州市| 武夷山市| 巴林左旗| 嘉峪关市| 镇巴县|