MyBatis預編譯
<select id="getUserById" resultMap="UserMap" parameterType="java.util.String"> select id,username,password,age,sex from t_user_info where id=#{id} </select>
打印SQL
select id,username,password,age,sex from t_user_info where id=?
MyBatis非預編譯
<select id="getUserById" resultMap="UserMap" parameterType="java.util.String"> select id,username,password,age,sex from t_user_info where id='${id}' </select>
打印SQL
select id,username,password,age,sex from t_user_info where id='1000001'
兩者實際執行執行SQL相同
select id,username,password,age,sex from t_user_info where id='10000001'
SQL注入攻擊情況下(String id = "10000001' OR '1'='1";)
預編譯打印SQL,實際執行SQL
select
id,username,password,age,sex
from
t_user_info
where
id=?
select
id,username,password,age,sex
from
t_user_info
where
id="10000001' OR '1'='1"(這裏爲方便理解將兩邊的'修改成了",實際爲id='10000001' OR '1'='1',
但是效果爲id="10000001' OR '1'='1")
如果沒有id爲“10000001' OR '1'='1”的信息返回null
非預編譯打印SQL,實際執行SQL
select
id,username,password,age,sex
from
t_user_info
where
id='10000001' OR '1'='1'
select
id,username,password,age,sex
from
t_user_info
where
id='10000001' OR '1'='1'
無論有沒有id爲“10000001',均返回所有用戶信息
總結
預編譯(#{})會將SQL提前編譯好,#{}位置爲佔位符,執行時候一個佔位符就對應一個變量,不會影響到SQL結
構,所以不會存在SQL注入問題;
非預編譯(${})不會提前編譯SQL,${}位置會直接將變量拼接進來,會影響到SQL的本身機構
Mybatis的SQL緩存
Mybatis的預編譯會將編譯後的SQL緩存起來,再次遇到相同的SQL會直接使用不會再次編譯
Mybatis的SQL優化
預編譯階段可以對sql語句進行優化;
預編譯可以將多個操作步驟合併成一個步驟,一般而言,越複雜的sql,編譯程度也會複雜,難度大,耗時,費性
能,而預編譯可以合併這些操作,預編譯之後DBMS可以省去編譯直接運行sql。(節選https://www.jianshu.com
/p/59155963d790)