PreparedStatement
1.Sql注入:由於jdbc程式在執行的過程中sql語句在拼裝時使用了由頁面傳入引數,如果使用者惡意傳入一些sql中的特殊關鍵字,會導致sql語句意義發生變化,這種攻擊方式就叫做sql注入,參考使用者註冊登入案例。
2.PreparedStatement是Statement的孩子,不同的是,PreparedStatement使用預編譯機制,在建立PreparedStatement物件時就需要將sql語句傳入,傳入的過程中引數要用?替代,這個過程回導致傳入的sql被進行預編譯,然後再呼叫PreparedStatement的setXXX將引數設定上去,由於sql語句已經經過了預編譯,再傳入特殊值也不會起作用了。
3.PreparedStatement使用了預編譯機制,sql語句在執行的過程中效率比Statement要高。
SQL隱碼攻擊:
由於dao中執行的SQL語句是拼接出來的,其中有一部分內容是由使用者從客戶端傳入,所以當使用者傳入的資料中包含sql關鍵字時,就有可能通過這些關鍵字改變sql語句的語義,從而執行一些特殊的操作,這樣的攻擊方式就叫做sql注入攻擊
PreparedStatement利用預編譯的機制將sql語句的主幹和引數分別傳輸給資料庫伺服器,從而使資料庫分辨的出哪些是sql語句的主幹哪些是引數,這樣一來即使引數中帶了sql的關鍵字,資料庫伺服器也僅僅將他當作引數值使用,關鍵字不會起作用,從而從原理上防止了sql注入的問題
PreparedStatement主要有如下的三個優點:
~1.可以防止sql注入
~2.由於使用了預編譯機制,執行的效率要高於Statement
~3.sql語句使用?形式替代引數,然後再用方法設定?的值,比起拼接字串,程式碼更加優雅.
示例程式碼:
package com.dzq.dao; import java.sql.Connection; import java.sql.PreparedStatement; import java.sql.ResultSet; import com.dzq.domian.User; import com.dzq.util.JDBCUtils; public class MySqlUserDao2 implements UserDao{ @Override public User findUserByUserName(String username) { String sql="select * from users where username=?"; Connection conn=null; PreparedStatement ps=null; ResultSet rs=null; try { conn=JDBCUtils.getConn(); ps=conn.prepareStatement(sql); ps.setString(1, username); rs=ps.executeQuery(); if(rs.next()){ User user=new User(); user.setId(rs.getInt("id")); user.setUsername(rs.getString("username")); user.setPassword(rs.getString("password")); user.setNickname(rs.getString("nickname")); user.setEmail(rs.getString("email")); return user; }else{ return null; } } catch (Exception e) { e.printStackTrace(); throw new RuntimeException(e); }finally{ JDBCUtils.close(rs, ps, conn); } } @Override public void addUser(User user) { String sql="insert into users values (null,?,?,?,?)"; Connection conn=null; PreparedStatement ps=null; ResultSet rs=null; try { conn=JDBCUtils.getConn(); ps=conn.prepareStatement(sql); ps.setString(1, user.getUsername()); ps.setString(2, user.getPassword()); ps.setString(3, user.getNickname()); ps.setString(4, user.getEmail()); //int count=stat.executeUpdate(sql); int count=ps.executeUpdate(); } catch (Exception e) { e.printStackTrace(); throw new RuntimeException(e); }finally{ JDBCUtils.close(rs, ps, conn); } } @Override public User findUserByUNAndPWD(String username, String password) { String sql="select * from users where username=? and password=?"; Connection conn=null; PreparedStatement ps=null; ResultSet rs=null; try { conn=JDBCUtils.getConn(); ps=conn.prepareStatement(sql); ps.setString(1, username); ps.setString(2, password); rs=ps.executeQuery(); if(rs.next()){ User user=new User(); user.setId(rs.getInt("id")); user.setUsername(rs.getString("username")); user.setPassword(rs.getString("password")); user.setNickname(rs.getString("nickname")); user.setEmail(rs.getString("email")); return user; }else{ return null; } } catch (Exception e) { e.printStackTrace(); throw new RuntimeException(e); }finally{ JDBCUtils.close(rs, ps, conn); } } }