1、SQL注入攻擊:
由於dao中執行的SQL語句是拼接出來的,其中有一部分內容是由用戶從客戶端傳入,所以當用戶傳入的數據中包含sql關鍵字時,就有可能通過這些關鍵字改變sql語句的語義,從而執行一些特殊的操作,這樣的攻擊方式就叫做sql注入攻擊
PreparedStatement利用預編譯的機制將sql語句的主干和參數分別傳輸給數據庫服務器,從而使數據庫分辨的出哪些是sql語句的主干哪些是參數,這樣一來即使參數中帶了sql的關鍵字,數據庫服務器也僅僅將他當作參數值使用,關鍵字不會起作用,從而從原理上防止了sql注入的問題
PreparedStatement主要有如下的三個優點:
1.可以防止sql注入
2.由於使用了預編譯機制,執行的效率要高於Statement
3.sql語句使用?形式替代參數,然后再用方法設置?的值,比起拼接字符串,代碼更加優雅.
PreparedStatement 與Statment比較
1)語法不同:PreparedStatement可以使用預編譯的sql,而Statment只能使用靜態的sql
2)效率不同: PreparedStatement可以使用sql緩存區,效率比Statment高
3)安全性不同: PreparedStatement可以有效防止sql注入,而Statment不能防止sql注入。
/** * PreparedStatement執行sql語句 * * */ public class Demo1 { /** * 增加 */ @Test public void testInsert() { Connection conn = null; PreparedStatement stmt = null; try { //1.獲取連接 conn = JdbcUtil.getConnection(); //2.准備預編譯的sql String sql = "INSERT INTO student(NAME,gender) VALUES(?,?)"; //?表示一個參數的占位符 //3.執行預編譯sql語句(檢查語法) stmt = conn.prepareStatement(sql); //4.設置參數值 /** * 參數一: 參數位置 從1開始 */ stmt.setString(1, "李四"); stmt.setString(2, "男"); //5.發送參數,執行sql int count = stmt.executeUpdate(); System.out.println("影響了"+count+"行"); } catch (Exception e) { e.printStackTrace(); throw new RuntimeException(e); } finally { JdbcUtil.close(conn, stmt); } } /** * 修改 */ @Test public void testUpdate() { Connection conn = null; PreparedStatement stmt = null; try { //1.獲取連接 conn = JdbcUtil.getConnection(); //2.准備預編譯的sql String sql = "UPDATE student SET NAME=? WHERE id=?"; //?表示一個參數的占位符 //3.執行預編譯sql語句(檢查語法) stmt = conn.prepareStatement(sql); //4.設置參數值 /** * 參數一: 參數位置 從1開始 */ stmt.setString(1, "王五"); stmt.setInt(2, 9); //5.發送參數,執行sql int count = stmt.executeUpdate(); System.out.println("影響了"+count+"行"); } catch (Exception e) { e.printStackTrace(); throw new RuntimeException(e); } finally { JdbcUtil.close(conn, stmt); } } /** * 刪除 */ @Test public void testDelete() { Connection conn = null; PreparedStatement stmt = null; try { //1.獲取連接 conn = JdbcUtil.getConnection(); //2.准備預編譯的sql String sql = "DELETE FROM student WHERE id=?"; //?表示一個參數的占位符 //3.執行預編譯sql語句(檢查語法) stmt = conn.prepareStatement(sql); //4.設置參數值 /** * 參數一: 參數位置 從1開始 */ stmt.setInt(1, 9); //5.發送參數,執行sql int count = stmt.executeUpdate(); System.out.println("影響了"+count+"行"); } catch (Exception e) { e.printStackTrace(); throw new RuntimeException(e); } finally { JdbcUtil.close(conn, stmt); } } /** * 查詢 */ @Test public void testQuery() { Connection conn = null; PreparedStatement stmt = null; ResultSet rs = null; try { //1.獲取連接 conn = JdbcUtil.getConnection(); //2.准備預編譯的sql String sql = "SELECT * FROM student"; //3.預編譯 stmt = conn.prepareStatement(sql); //4.執行sql rs = stmt.executeQuery(); //5.遍歷rs while(rs.next()){ int id = rs.getInt("id"); String name = rs.getString("name"); String gender = rs.getString("gender"); System.out.println(id+","+name+","+gender); } } catch (Exception e) { e.printStackTrace(); throw new RuntimeException(e); } finally { //關閉資源 JdbcUtil.close(conn,stmt,rs); } } }
eg:模擬登陸
/** * 模擬用戶登錄效果 * * */ public class Demo2 { //模擬用戶輸入 //private String name = "ericdfdfdfddfd' OR 1=1 -- "; private String name = "eric"; //private String password = "123456dfdfddfdf"; private String password = "123456"; /** * Statment存在sql被注入的風險 */ @Test public void testByStatement(){ Connection conn = null; Statement stmt = null; ResultSet rs = null; try { //獲取連接 conn = JdbcUtil.getConnection(); //創建Statment stmt = conn.createStatement(); //准備sql String sql = "SELECT * FROM users WHERE NAME='"+name+"' AND PASSWORD='"+password+"'"; //執行sql rs = stmt.executeQuery(sql); if(rs.next()){ //登錄成功 System.out.println("登錄成功"); }else{ System.out.println("登錄失敗"); } } catch (Exception e) { e.printStackTrace(); throw new RuntimeException(e); } finally { JdbcUtil.close(conn, stmt ,rs); } } /** * PreparedStatement可以有效地防止sql被注入 */ @Test public void testByPreparedStatement(){ Connection conn = null; PreparedStatement stmt = null; ResultSet rs = null; try { //獲取連接 conn = JdbcUtil.getConnection(); String sql = "SELECT * FROM users WHERE NAME=? AND PASSWORD=?"; //預編譯 stmt = conn.prepareStatement(sql); //設置參數 stmt.setString(1, name); stmt.setString(2, password); //執行sql rs = stmt.executeQuery(); if(rs.next()){ //登錄成功 System.out.println("登錄成功"); }else{ System.out.println("登錄失敗"); } } catch (Exception e) { e.printStackTrace(); throw new RuntimeException(e); } finally { JdbcUtil.close(conn, stmt ,rs); } } }
