突然意識到sql語句的獨特語義要和代碼分離,我們就不能夠在代碼中寫sql語句!!比如我要用${}在MyBatis的sql中拼接排序類型的時候,我就不能夠在Java代碼中直接寫參數字符串爲Order By哪兒個類型
#{}和${}的基本不同我就不想說了,這裏要說的是進一步對佔位符和字符拼接的字面語義的領悟!!
佔位符:佔位符就是在某個地方佔領一個位置,把它單獨作爲某個東西,比如這裏就是把它作爲 值。
字符拼接:字符拼接就是簡單的對字符串拼接。沒有特殊的其它含義。
問題出現:
不知道大家有沒有想過一個問題
SELECT * FROM #{tableName} //有沒有想過??
上面我們已經說過了佔位符的意義就是作爲值的存在,所以如果作爲值的話,那麼發送的sql語句就是這樣的:
SELECT * FROM ?
大家都知道MyBatis中這種sql語句是要經過預編譯的,雖然MyBatis並沒有真正的用上數據庫的預編譯功能(因爲數據庫的預編譯默認是關閉的。。。而且MyBatis底層也是使用PreparedStatement和Statement這兩個對象,大家可以參考我的一篇博客Presatement和Statement深入理解+MySQL的預編譯)。
大家都知道,帶問號的sql語句是要傳遞參數的,好!!假如!!我們傳入了參數user
,那麼查詢語句就是這樣的:
SELECT * FROM 'user'
請問,這種sql語句能夠執行成功嗎??試試就知道了!!
很明顯語法錯誤!!
那麼有什麼辦法能夠解決呢??
沒錯!!!
${}
能夠解決這個問題,${}
的功能是直接進行字符串拼接。這也是爲什麼${}
不能夠防止一般的sql注入攻擊。因爲它是拼接啊!!
這樣寫就行了:
SELECT * FROM ${tableName} //如果傳入基本類型如字符串時就要把tableName改爲value才能夠成功取值。
普通sql注入過程:
SELECT * FROM user WHERE username like '' OR 'XX'='XX' OR ''
- 1
當用戶輸入:
' OR 'XX'='XX' OR '
- 1
這樣就出現問題了。。。
最後總結下:
一般${}用在我們能夠確定值的地方,也就是我們程序員自己賦值的地方。
而#{}一般用在用戶輸入值的地方!!