在一般的 Java 程式裡如果要插入一筆資料到資料表中,最基本的方法都是用 java.sql.Statement 去做,譬如:
Statement state = connection.createStatement();
state.executeUpdate("SQL 語法");
通常上面的 SQL 語法會寫的太凌亂,譬如太多的單引號和雙引號交錯導致可讀性不易,例如
state.executeQuery("INSERT INTO temp(account, user, password) VALUES('" + account + "','" + username + "','" + password + "')"); //以上的三個變數都為字串
以上有個替代方法就是利用 java.sql.PreparedStatement
可以很簡單的表示成以下
String sql = "INSERT INTO temp(account, user, password) VALUES(?, ? ,?)";
PreparedStatement prestate = connection.prepareStatement(sql); //先建立一個 SQL 語句並回傳一個 PreparedStatement 物件
prestate.setString(1, account); //對應到第一個問號
prestate.setString(2, user); //對應到第二個問號
prestate.setString(3, password); //對應到第三個問號
prestate.executeUpdate(); //真正執行
以上的參數都為字串型態,當然除了字串以外還有其他型態,例如 setInt()...等
而在使用 Statement 物件時,通常最常使用的
executeUpdate、executeQuery()、execute()
在 PreparedStatement 也是正常使用的,值得提醒的是 execute()該方法會回傳布林值
若為 true 代表結果為 ResultSet 物件,通常都是執行查詢。
若為 false 代表結果會回傳一個整數或是沒結果,表示的是更新的資料數。
說到用 PreparedStatement 的好處還有防止 SQL injection 的攻擊
不過如果可以的話其實可以在使用者輸入的資料進行篩選,例如
account.matches("[a-z0-9]+")
如此一來或多或少可以防止 SQL injection。
接下來介紹一些更進階的技巧,如果要製作一個專門處理資料庫操作的共用元件
這樣可以減少在 Servlet 或是 JSP 中雜亂的資料庫操作程式碼
但是由於在設定資料參數值的時候可能有多種的型態和多種的操作,如上所述
這時候可以寫一個共通的 method 來執行全部的 PreparedStatement 操作
public boolean exceuteQueUpd(String sql, Object[] params)
{ //sql 為語法, params 的 Object 型態陣列 為所有參數
if(connection == null){
if(!getConnection()){
return false;
}
}
try{
pstate = connection.prepareStatement(sql, ResultSet.TYPE_SCROLL_INSENSITIVE, ResultSet.CONCUR_READ_ONLY);
for(int i=0;i<params.length;i++){
pstate.setObject(i+1, params[i]);//資料參數的設定是從1開始
}
return pstate.execute();
//因為有可能會執行任何一種的SQL 語句,所以統一使用 execute
//而非特定的 executeUpdate() 或是 executeQuery()
}catch(SQLException sqle){
System.out.println(sqle);
return false;
}
}
以上的片斷程式,會傳入一個 Object 型態的陣列,簡單說該陣列包含了所有?的資料
接著用迴圈將 Object 的每個參數進行設定,用 setObject 方法
以下以一個範例執行以上定一的 exceuteQueUpd()method
db.exceuteQueUpd("SELECT * FROM member WHERE account = ? AND ip = ?",
new Object[]{new String("ayu780129"), new Integer(ip)});
再舉一個例子
db.exceuteQueUpd("UPDATE member SET ip = ? WHERE account = ?", new Object[]{new Integer(ip), new String("ayu780129")});
以上就如同一般的 PreparedStatement 使用一樣,不同的是不用再依據資料的型態做不同的設定,如 setInt、setString、setDouble 等等。
只要將所有要設定的參數資料一併都放數 Object 陣列即可,就解決的資料型態不固定的問題了
第一個例子如果沒發生例外會回傳 true,代表可以透過 PreparedStatement 的 getResultSet() 取得 ResultSet
第二個例子的話則是會回傳 false,可以透過 PreparedStatement 的 getUpdateCount()取得更新的資料數
所以可以透過執行 exceuteQueUpd() 回傳的布林值判斷,並加以處理
之後再介紹更多 java SQL 的說明
大大請教,我用你的方法做INSERT後
回覆刪除發現資料有錯誤
但因資料量大無法一一驗證
如何把INSERT的錯誤SQL字串取出來
煩請解惑~感恩!