PrepareStatement是 Statement的子接口,能夠傳入帶佔位符的 SQL語句,提供了補充佔位符變量的方法。
使用 prepareStatement:java
1. 建立 PrepareStatement對象sql
2. 調用 PrepareStatement的 setXxx(int index, Object val) 設置佔位符的值,索引值從1開始。
3. 執行 SQL語句: executeQuery() 或 executeUpdate().。執行時不須要再傳入 SQL 語句。數據庫
/** * PrepareStatement是 Statement的子接口,能夠傳入帶佔位符的 SQL語句 * 提供了補充佔位符變量的方法。 * * 使用 prepareStatement: * 1. 建立 PrepareStatement對象 * String sql = "INSERT INTO Student VALUES(?,?,?,?,?,?)"; * PrepareStatement ps = conn.prepareStatement(sql); * 2. 調用 PrepareStatement的 setXxx(int index, Object val) 設置佔位符的值 * 索引值從1開始。 * 3. 執行 SQL語句: executeQuery() 或 executeUpdate(). * 執行時不須要再傳入 SQL 語句。 */ @Test public void test8() { Connection conn = null; PreparedStatement preparedStatement = null; try { //獲取數據庫鏈接 conn = getConnection2(); //設置 SQL語句 String sql = "INSERT INTO Student(Sno, Sname, Ssex, Sage, Sdept, S_entrance) " + "VALUES(?,?,?,?,?,?)"; //爲佔位符賦值 preparedStatement = conn.prepareStatement(sql); preparedStatement.setString(1, "201415411"); preparedStatement.setString(2, "李明"); preparedStatement.setString(3, "男"); preparedStatement.setInt(4, 20); preparedStatement.setString(5, "CS"); preparedStatement.setDate(6, Date.valueOf("2014-09-09")); //執行 SQL語句 preparedStatement.executeUpdate(); } catch(Exception e) { e.printStackTrace(); } finally { if(preparedStatement != null) { try { preparedStatement.close(); } catch(Exception e) { e.printStackTrace(); } } if(conn != null) { try { conn.close(); } catch(Exception e) { e.printStackTrace(); } } } } //getConnection2()方法 public Connection getConnection2() throws Exception { //1.準備鏈接數據庫的4個字符串 //1.1 建立Properties對象 Properties properties = new Properties(); //1.2 獲取jdbc.properties對應的輸入流 java.io.InputStream in = this.getClass().getClassLoader().getResourceAsStream("jdbc.properties"); //1.3 加載文件 properties.load(in); //1.4 給字符串賦值 String driver = properties.getProperty("driver"); String jdbcUrl = properties.getProperty("jdbcUrl"); String user = properties.getProperty("user"); String password = properties.getProperty("password"); //2.加載數據庫驅動程序(對應的Driver實現類中有註冊驅動的靜態代碼塊) Class.forName(driver); //3.經過DriverManager的getConnection方法獲取數據庫鏈接 return DriverManager.getConnection(jdbcUrl, user, password); }
SQL 注入是利用某些系統沒有對用戶輸入的數據進行充分的檢查,而在用戶輸入數據中注入非法的 SQL 語句段或命令,從而利用系統的 SQL 引擎完成惡意行爲的作法。緩存
對於 Java 而言,要防範 SQL 注入,只要用 PreparedStatement 取代 Statement 就能夠了。性能優化
以下程序,使用Statement,有SQL注入風險函數
/** * 用戶表中有兩列:用戶username和密碼password * 只有當用戶和密碼都正確時,登錄成功,不然不成功 * */ @Test public void test9() { //當用戶名和密碼設置以下,表中不存在這個用戶名和密碼,可是任然能夠登陸成功 String username = "a' OR password = "; String userpassword = " OR '1'='1"; String sql = "SELECT * FROM Users WHERE username = '" + username +"' AND " + "password= '" + userpassword + "'"; Connection conn = null; Statement statement = null; ResultSet resultSet = null; try { conn = getConnection2(); statement = conn.createStatement(); resultSet = statement.executeQuery(sql); if(resultSet.next()) { System.out.println("登錄成功!"); } else { System.out.println("用戶名和密碼不匹配或用戶不存在"); } } catch(Exception e) { e.printStackTrace(); } finally { if(resultSet != null) { try { resultSet.close(); } catch(Exception e) { e.printStackTrace(); } } if(statement != null) { try { statement.close(); } catch(Exception e) { e.printStackTrace(); } } if(conn != null) { try { conn.close(); } catch(Exception e) { e.printStackTrace(); } } } }
當用戶名和密碼這樣設置時:性能
String username = "a' OR password = ";
String userpassword = " OR '1'='1";學習
儘管表中沒有這個用戶名和密碼,但依然能夠登陸,此時SQL語句爲:優化
SELECT * FROM Student WHERE username = 'a' OR password = ' AND Sno= ' OR '1'='1'this
如上,username的值爲 a,password的值爲 AND Sno=。整個WHERE條件是或條件判斷,而 '1'='1' 是恆成立的,因此這條語句會執行。
使用PreparedStatement,將有效的解決注入問題
/** * 使用 PreparedStatement將有效的解決注入問題 * */ @Test public void test10() { String username = "a' OR Sno = "; String userpassword = " OR '1'='1"; String sql = "SELECT * FROM Users WHERE username = ?" + " AND password= ?"; Connection conn = null; PreparedStatement preparedStatement = null; ResultSet resultSet = null; try { conn = getConnection2(); preparedStatement = conn.prepareStatement(sql); preparedStatement.setString(1, username); preparedStatement.setString(2, userpassword); resultSet = preparedStatement.executeQuery(); if(resultSet.next()) { System.out.println("登錄成功!"); } else { System.out.println("用戶名和密碼不匹配或用戶不存在"); } } catch(Exception e) { e.printStackTrace(); } finally { if(resultSet != null) { try { resultSet.close(); } catch(Exception e) { e.printStackTrace(); } } if(preparedStatement != null) { try { preparedStatement.close(); } catch(Exception e) { e.printStackTrace(); } } if(conn != null) { try { conn.close(); } catch(Exception e) { e.printStackTrace(); } } } }
JDBC學習筆記:
1. 獲取數據庫鏈接 http://my.oschina.net/daowuming/blog/704243
2. 經過Statement執行更新、查詢操做 http://my.oschina.net/daowuming/blog/704384
3. 使用PrepareStatement ----當前----
4. 使用ResultSetMetaData 對象處理結果集元數據 http://my.oschina.net/daowuming/blog/704487
5. 使用DatabaseMetaData獲取數據庫信息 http://my.oschina.net/daowuming/blog/704553
6. BLOB http://my.oschina.net/daowuming/blog/704593
7. 處理事務與隔離級別 http://my.oschina.net/daowuming/blog/704611
8. 批量處理 http://my.oschina.net/daowuming/blog/704641
9. 數據庫鏈接池 http://my.oschina.net/daowuming/blog/704700
10. 調用函數與存儲過程 http://my.oschina.net/daowuming/blog/704813