每天資訊mybatis的$和#詳解分析

菜單

mybatis的$和#詳解分析

mybatis的$和#詳解分析

Cause: java。sql。SQLSyntaxErrorException: Unknown column ‘itlezhi’ in ‘where clause’

好久之前的mybatis原始碼閱讀還有一點沒有完成,今天準備來收個尾,結果一執行測試程式碼就報錯了。

#01報錯分析

報錯程式碼與異常資訊如下圖:

mybatis的$和#詳解分析

第一瞬間我竟然不知道錯在哪裡了,感覺就是很正常的一句sql啊,我直接把錯誤資訊“Cause: java。sql。SQLSyntaxErrorException: Unknown column ‘itlezhi’ in ‘where clause’”百度一下,答案是把$換成#就好了。就馬上試了下竟然成功了。

有的答案還說了sql中定義的型別是int型的可以不用加引號,但是如果是字串型別的,必須加引號。從這句話中我總算知道我的sql錯哪裡了。

Mybatis的$把name引數對映到sql語句中竟然沒有加引號,以至於sql報錯。

#02聯想測試

同時就想到之前經常聽到的面試題:$與#的區別、mybatis如何防止sql注入等。如果我把引數itlezhi換成’itlezhi’ or 1=1就可以實現sql注入了。

經過測試確實可以,只不過這裡我呼叫的selectOne方法,所以直接報錯了,改成selectList方法則成功返回了所有的資料。

如果把$快取#則一條資料都沒有查出來,實現了防止sql注入的功能。那麼在原始碼中是如何處理呢?

#03原始碼跟蹤

從之前原始碼知道sql來源於,把$換成#之後直接跟進到建立boundSql的地方,可以看到在rootSqlNode的apply之後sql如下圖:

mybatis的$和#詳解分析

透過debug的sqlBuilder可以看出來SqlNode的apply只處理了$,#{name}還沒有進行處理。

那麼#是在哪裡處理的呢?就在緊接著的SqlSourceBuilder中。在上圖中apply之後馬上初始化了一個SqlSourceBuilder物件並執行了parse方法。

SqlSourceBuilder的parse方法原始碼如下圖:

mybatis的$和#詳解分析

又見到GenericTokenParser這個類了。簡單介紹下這個類,這個類可以當成一個佔位符解析類,接受3個引數分別表示佔位符起始、結束、處理解析結果類。至於處理邏輯在TextSqlNode的apply已經詳細介紹過了。這次如上圖就會解析#{}。處理邏輯也在上圖原始碼中,解析出來的處理邏輯是把#{}的內容儲存下來,並用?替換#{}。

我們可以看到處理完成後的結果如下圖:

mybatis的$和#詳解分析

Sql儲存的處理後的sql語句,這個sql是需要預處理才能執行的,parameterMappings中記錄著需要預處理的引數。

然後繼續跟進原始碼直到執行sql之前,生成Statement的原始碼如下圖:

mybatis的$和#詳解分析

生成的boundSql在建立StatementHandler 時才使用。再透過生成的StatementHandler 創建出來Statement。

從上圖可以看到Statement的關鍵屬性。ClientPreparedStatement重寫了toString方法,展示了預處理後的sql,實際上的sql是“select id,name,age,ids from member where id = 5 and name = ?”。

columnNames、columnMap分別表示預處理需要的引數和對應的值。columnNames集合中第一個元素值是1和columnMap中1對應的值相當於下面這句話:

preparedStatement。setString(1, “‘itlezhi’ or 1=1”);

所以最終的執行結果sql:“select id,name,age,ids from member where id = 5 and name = ‘’‘itlezhi’‘ or 1=1’”。這樣的sql一般都查不出來資料了,實現了防止sql注入。

IT樂知——程式設計師的指路名師。這個世界幾乎不合所有人的夢想。只是有些人可以學會遺忘,有些人卻可以堅持。一切的成就不過是源於一個夢想和毫無根據的自信,只要能夠堅持“探索、嘗試”和保持“堅毅、自尊、仁慈”,就必定能夠創出自己的天地。對於程式設計師來說,學習永無止境,成長永不停步。持續汲取知識,充盈身心,方可於IT行業馳騁。而IT樂知就可以幫程式設計師解決成長道路上的任何難題。

PROMPT溫馨提示

Java程式設計師日常學習筆記,如理解有誤歡迎各位交流討論!

更多Java面試題,小程式:IT面試題練習…

mybatis的$和#詳解分析