4 回答

TA貢獻1772條經驗 獲得超5個贊
首先通過下面兩條sql及打印的執行sql,清楚明了的看一下它們的區別:
<select id="selectUserInfo" parameterType="java.util.Map" resultType="java.util.Map">
select
*
from
user
where
userId=${id} password=#{pwd}
</select>12345678
假設入參傳入的是1,打印執行sql如下:
Preparing:select * from user where id=1 and password=111111
<select id="selectUserInfo" parameterType="java.util.Map" resultType="java.util.Map">
select
*
from
user
where
userId=#{id} and password=#{pwd}
</select>12345678
同樣入參傳入1,打印的執行sql如下:
Preparing:select * from user where id=? and password=?
Parameters:1(String),111111(String)
MyBatis啟用了預編譯功能,在SQL執行前,會先將上面的SQL發送給數據庫進行編譯;執行時,如果入參為#{}格式的,將入參替換編譯好的sql中的占位符“?”;如果入參格式為${},則直接使用編譯好的SQL就可以了。因為SQL注入只能對編譯過程起作用,所以使用#{}入參的方式可以很好地避免了SQL注入的問題。
mybatis預編譯底層實現原理
MyBatis是如何做到SQL預編譯的呢?其實在框架底層,是JDBC中的PreparedStatement類在起作用,PreparedStatement是我們很熟悉的Statement的子類,它的對象包含了編譯好的SQL語句。這種“準備好”的方式不僅能提高安全性,而且在多次執行同一個SQL時,能夠提高效率。原因是SQL已編譯好,再次執行時無需再編譯。
總結
#{}:相當于JDBC中的PreparedStatement
${}:是輸出變量的值
簡單說,#{}是經過預編譯的,是安全的;${}是未經過預編譯的,僅僅是取變量的值,是非安全的,存在SQL注入。
番外(sql注入)
還是以上面的兩條sql為例,入參id的值傳入“1 or userId=2”,入參pwd的值傳入“111111”。以#{}格式傳入入參后的執行sql:
select * from user where userId=”1 or userId=2” and password = “111111”;
以${}格式傳入入參后的執行sql:
select * from user where userId=1 or userId=2 and password = 111111;
很顯然,以${}格式傳入入參后的執行sql打亂了我們的預期sql格式及查詢條件,從而實現sql注入。所以,除了order by 等需要傳入數據庫字段等的入參使用${},其他的盡量使用#{}。

TA貢獻1796條經驗 獲得超10個贊
mybatis預編譯底層實現原理
MyBatis是如何做到SQL預編譯的呢?其實在框架底層,是JDBC中的PreparedStatement類在起作用,PreparedStatement是我們很熟悉的Statement的子類,它的對象包含了編譯好的SQL語句。這種“準備好”的方式不僅能提高安全性,而且在多次執行同一個SQL時,能夠提高效率。原因是SQL已編譯好,再次執行時無需再編譯。
總結
#{}:相當于JDBC中的PreparedStatement
${}:是輸出變量的值
簡單說,#{}是經過預編譯的,是安全的;${}是未經過預編譯的,僅僅是取變量的值,是非安全的,存在SQL注入。
- 4 回答
- 0 關注
- 1254 瀏覽
添加回答
舉報