JDBC04----預編譯語句介紹
sql的拼接很麻煩,且容易出錯,因此就可以使用預編譯語句。
介面java.sql.Statement有兩個子介面:CallableStatement,PreparedStatement
有兩種型別的sql語句:
1.靜態sql
在執行之前就知道了sql語句的形式。
2.動態sql
一. Statement介面的實現類
1. PreparedStatement
- PreparedStatement用於預編譯模板SQL語句,在執行時接受SQL輸入引數。eg:PreparedStatement ps=conn.preparedStatement(sql);
- 在效能和程式碼靈活性上有顯著的提高
- PreparedStatement物件使用?作為佔位符,即引數標記;eg: select *from stu where id=?; insert into stu value(?,?,?);
- 使用setXXX(index,value)方法將值繫結到引數中,每個引數標記是其順序位置引用,注意index從1開始;eg:ps.setInt(1,stu.getId());
- PreparedStatement物件執行sql語句:executeQuery()、executeUpdate(),注意,他們沒有引數; eg:ps.executeUpdate();
2. 舉例
public Stu get(int id) { ResultSet resultSet=null; Connection connection=null; PreparedStatement pStatement=null; Stu student=new Stu(); try { Class.forName(JDBCUtil.driverName); connection=JDBCUtil.getConnection(); String sql="select *from stu where id=?"; pStatement=connection.prepareStatement(sql); pStatement.setInt(1, id);//note這裡的id時傳入的,如果傳入引數是student,就可以改成pStatement.setInt(1,student.getId()) resultSet=pStatement.executeQuery(); if(resultSet.next()) { student.setId(resultSet.getInt("id")); student.setName(resultSet.getString("name")); student.setAge(resultSet.getInt("age")); return student; } } catch (Exception e) { // TODO Auto-generated catch block e.printStackTrace(); }finally { JDBCUtil.close(connection, pStatement, resultSet); } return null; }
3. 如果沒有使用預編譯語句
如果沒有使用預編譯語句的話,假設已經有一個靜態的sql語句了,每一次查詢的age不同,都會往預編池中寫入一次資料。
4. 如果使用預編譯語句
引數統一用?表示,這樣預編譯池中就不會多次寫入資料了。---------(當很多人操作資料庫時,這回很麻煩的)
note: mysql不支援預編譯池,oracle支援預編譯池。
6. 使用預編譯可以防止SQL注入。
(1)什麼是SQL注入
就是通過把SQL命令插入到WEB表單提交或輸入域名或頁面請求的查詢字串,最終達到欺騙伺服器執行惡意的SQL語句。(說人話:就是一些錯誤的sql語句,導致了錯誤的sql語義被執行了)
(2)SQL注入舉例
上面是一個使用者登陸的程式碼,當用戶名如上定義時,雖然表中沒有這個使用者,但是最終的結果會發現列印了登陸成功。打印出這一條sql語句:
因此,看到拼接結果可以知道前面那個條件已經滿足了,就不會管or後面的語句了:即name=‘’已經成立了。
如果使用預編譯,因為它執行的時候會把單引號轉義。----也就是防止SQL注入的根源
如果使用預編譯:
(3)為什麼PrepareStaet就能防止注入
是因為它把單引號轉義了,變成了\,這樣一來,就無法截斷SQL語句,進而無法拼接SQL語句,基本上沒有辦法注入了。
二. JDBC呼叫輸出引數儲存過程----CallableStatement
1. 建立一個儲存過程
測試下:
2. 使用Java程式來實現呼叫
public void call(){ Connection connection=JDBCUtil.getConnection(); CallableStatement cStatement; try { cStatement = connection.prepareCall("{call getName(?,?)}"); cStatement.setInt(1, 2); cStatement.registerOutParameter(2, Types.VARCHAR); cStatement.execute(); String name=cStatement.getString(2); System.out.println(name); } catch (SQLException e) { // TODO Auto-generated catch block e.printStackTrace(); } }
參考文獻
https://ke.qq.com/course/339214