預編譯SQL語句(動態SQL)
預編譯SQL語句與靜態SQL語句的區別
預編譯語句PreparedStatement 是java.sql中的一個接口,它是Statement的子接口。SQL語句的執行就是靠Statement執行的。
- 靜態SQL語句:
//4.獲取執行sql對象
statement = connection.createStatement();
//5.執行sql
resultSet = statement.executeQuery(sql);
在獲取到Statement對象後,SQL語句被髮送到DBMS,完成了解析、檢查、編譯等工作,如果沒有錯誤纔可以執行
2. 預編譯SQL語句:
//賦值語句使用?替換
String sql = "select *from user where username = ? and password = ?;";
psmt = connection.prepareStatement(sql);
//爲?賦值
psmt.setString(1,username);
psmt.setString(2,password);
resultSet = psmt.executeQuery();
在獲取到PreparedStatement 對象,前SQL語句被先發送到DBMS,完成了解析、檢查、編譯等工作,如果沒有錯誤將返回PreparedStatement 對象用於執行SQL
3. SQL注入案例:
SELECT * FROM user WHERE username='admin' AND password='passwd'
--當輸入了下面的用戶名和密碼,上面的SQL語句變成:
SELECT * FROM user WHERE username=''or 1=1 #' AND password=''
SELECT * FROM user WHERE username=‘or 1=1 #’ AND password=’’
由於是直接拼接好的SQL語句發送到數據庫,所以等價於
SELECT * FROM user
可見如果採用了Statement執行SQL語句,將直接發送SELECT * FROM user WHERE username=’‘or 1=1 #’ AND password=’'到數據庫,並且被DBMS解析後變成SELECT * FROM user,直接被繞過驗證了,這是多麼可怕的事情。
但是如果採用的是預編譯語句處理,則發送到DBMS的是
SELECT * FROM user WHERE username=? AND password=?
setXXX之後的語句變成
select * FROM user WHERE username=\'\ or 1=1 #\'\ AND password=''
其中 單引號被MySQL的語法給轉義了,導致無法匹配上數據庫。
總之:相比正常的Statement執行SQL,預編譯SQL的方法更爲高效,體現在如果一條SQL語句要被執行多遍,則只會被DBMS檢查一次,相比正常執行SQL的效率提高了;PreparedStatement還可以防止SQL注入問題,安全性也更高。
如有出入,懇請指教