下面是MyBatis一個Dao配置mysql
<select id="findRank" parameterType ="String" resultType="String">
SELECT u.name FROM UserInfo u
where 1=1
and u.UserID=#{userID} ;
</select>
打印出執行的SQL語句sql
SELECT u.name FROM UserInfo u where 1=1 and u.UserID=?
這是由於MyBatis啓用了預編譯功能,在SQL執行前,會先將上面的SQL發送給數據庫進行編譯;執行時,直接使用編譯好的SQL,替換佔位符「?」就能夠了。由於SQL注入只能對編譯過程起做用,因此這樣的方式就很好地避免了SQL注入的問題。
【底層實現原理】
MyBatis是如何作到SQL預編譯的呢?其實在框架底層,是JDBC中的PreparedStatement類在起做用,PreparedStatement是咱們很熟悉的Statement的子類,它的對象包含了編譯好的SQL語句。這種「準備好」的方式不只能提升安全性,並且在屢次執行同一個SQL時,可以提升效率。緣由是SQL已編譯好,再次執行時無需再編譯。數據庫
話說回來,是否咱們使用MyBatis就必定能夠防止SQL注入呢?固然不是,請看下面的代碼:安全
<select id="findRank" parameterType ="String" resultType="String">
SELECT u.name FROM UserInfo u
where 1=1
and u.UserID=${userID} ;
</select>
假設userID=1,將SQL打印出來是這樣的:框架
SELECT u.name FROM UserInfo u where 1=1 and u.UserID=1
假如:
userID=1;drop table UserInfo ;那麼sql是這樣的測試
SELECT u.name FROM UserInfo u where 1=1 and u.UserID=1;drop table UserInfo ;
測試結果
SELECT u.name FROM UserInfo u where 1=1 and u.UserID=1;drop table UserInfo;
### Cause: com.mysql.jdbc.exceptions.jdbc4.MySQLSyntaxErrorException: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'drop table UserInfo' at line 3 直接報異常,你應該慶幸mybaties作了處理,可是無論怎麼說${xxx}是沒法阻止SQL注入的。
「${xxx}」
缺點: 直接參與SQL編譯,不能避免注入攻擊。
優勢:及到動態表名和列名時,只能使用「${xxx}」這樣的參數格式
注意: 這樣的參數須要咱們在代碼中手工進行處理來防止注入。ui
「#{xxx}「
至關於JDBC中的PreparedStatement
${}:是輸出變量的值
優勢:#{}是通過預編譯的,是安全的;spa