SQL語句預編譯的個人理解

預編譯SQL語句(動態SQL)

預編譯SQL語句與靜態SQL語句的區別

預編譯語句PreparedStatement 是java.sql中的一個接口,它是Statement的子接口。SQL語句的執行就是靠Statement執行的。

  1. 靜態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注入問題,安全性也更高。

如有出入,懇請指教

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章