作者:程式猿的內心獨白
https://m.toutiaocdn.com/i6685496024770806280
這是一次代碼優化程序中發現的問題,在功能優化后發現部分資料查不到出來了,問題就在于一條sql上的#和$,
下圖為兩條sql:

從圖上可以看出 wwlr.LabelId in(${showLabels}) 和 wwlr.LabelId in(#{showLabels}),其中showLabels是傳進來一個字串型別的引數,引數的樣子是這樣的“4,44,514”,問題就出在這個引數傳進來后#和$處理的方式是不一樣的,
區別

1、#{ }是預編譯處理,MyBatis在處理#{ }時,它會將sql中的#{ }替換為?,然后呼叫PreparedStatement的set方法來賦值,傳入字串后,會在值兩邊加上單引號,如上面的值 “4,44,514”就會變成“ '4,44,514' ”;
2、${ }是字串替換, MyBatis在處理${ }時,它會將sql中的${ }替換為變數的值,傳入的資料不會加兩邊加上單引號,
注意:使用${ }會導致sql注入,不利于系統的安全性!
SQL注入:就是通過把SQL命令插入到Web表單提交或輸入域名或頁面請求的查詢字串,最終達到欺騙服務器執行惡意的SQL命令,
常見的有匿名登錄(在登錄框輸入惡意的字串)、借助例外獲取資料庫資訊等
應用場合:
1、#{ }:主要用戶獲取DAO中的引數資料,在映射檔案的SQL陳述句中出現#{}運算式,底層會創建預編譯的SQL;
2、${ }:主要用于獲取組態檔資料,DAO介面中的引數資訊,當$出現在映射檔案的SQL陳述句中時創建的不是預編譯的SQL,而是字串的拼接,有可能會導致SQL注入問題.所以一般使用$接收dao引數時,這些引數一般是欄位名,表名等,例如order by {column},
注:
${}獲取DAO引數資料時,引數必須使用@param注解進行修飾或者使用下標或者引數#{param1}形式;
{}獲取DAO引數資料時,假如引數個數多于一個可有選擇的使用@param,
問題分析

其實剛開始我也沒太去看sql里的#和$,我把sql放到資料庫跑一切正常,所以我就將代碼的執行sql輸出到控制臺了,具體是這么一個輸出sql的組態檔:

輸出后,終于發現了問題在哪里,,,,
看了上面的區別介紹,相信大家其實都應該知道區別在哪里,我們的問題在哪里,其實就是sql在in的時候 ,里面的資料被加了兩個雙引號,“wwlr.LabelId in(4,44,514)就會變成 wwlr.LabelId in('4,44,514' );所以導致部分資料查不到了,
解決辦法

1、快速解決
最快的方法就是把#直接替換成$,這樣問題應該就可以解決了,
但是,我很無語,我確沒有解決,
本地跑代碼一點問題都沒有,部署到公司的docker上問題一樣沒解決,給人的感覺就是代碼根本沒有從#變$,
大家都知道$其實是有危險性,會容易被sql注入,具我所知道,我們公司的docker是會加一層防止 sql注入的功能 ,所以不知道是不是這個功能把的$無效掉了,
當然,我也沒有去再到服務上打出sql來看一下,因為本來$就是不太安全的,所以我換了一種方式處理,
2、foreach標簽的使用
foreach標簽主要用于構建in條件,他可以在sql中對集合進行迭代,
先來看看語法:

通過上圖,大家也應該也了解和使用這個標簽了吧,
那對于我們專案中的改造,其實就是把原來傳進來的字符型引數變成List
推薦去我的博客閱讀更多:
1.Java JVM、集合、多執行緒、新特性系列教程
2.Spring MVC、Spring Boot、Spring Cloud 系列教程
3.Maven、Git、Eclipse、Intellij IDEA 系列工具教程
4.Java、后端、架構、阿里巴巴等大廠最新面試題
覺得不錯,別忘了點贊+轉發哦!
轉載請註明出處,本文鏈接:https://www.uj5u.com/houduan/165056.html
標籤:Java
上一篇:Flink 如何分流資料
下一篇:Java--注解
