(記錄)mysql分頁查詢,參數化過程的坑


  在最近的工作中,由於歷史遺留,一個分頁查詢沒有參數化,被查出來有sql注入危險,所以對這個查詢進行了參數化修改。

  一看不知道,看了嚇一跳,可能由於種種原因,分頁查詢sql是在存儲過程中拼接出來的,where之后的條件也是在代碼中先進行拼接,然后作為整體參數在傳入存儲過程里,在存入過程里又進行一次拼接。這樣的話就有sql注入的潛在危險,盡管在拼接where之前進行的查詢條件的驗證。

  大家都明白,參數化是防止sql注入的有效方法,然后就對這個分頁查詢進行大刀闊斧的改革。

  思路一:1、對原先的代碼中拼接的where條件,不進行直接的賦值拼接。而是拼接成帶@符號的參數。並且給參數賦值;例如:

if (Num > 0)
{
    sbWhere.Append(" AND s.SysNo=").Append(Num.Value);
}
改
if (Num > 0)
{
    sbWhere.Append(" AND s.SysNo = @SysNo ");
    paras.Add(new MySqlParameter("@SysNo", Num.Value));
}

      2、給存儲過程添加參數

      3、用SetParameters(paras.ToArray())方法直接把參數paras傳給存儲過程

  結論:根本走不通,因為我們的查詢條件是動態拼接的,沒辦法動態給存儲過程定義傳入參數,這個思路直接給pass掉了;

  小結:雖然這個方法走不通,但是在這個思路的第一步,是我們可以繼續用的,這個是沒有問題的。既然沒有辦法動態定義存儲過程參數,我們就不能再存儲過程中拼接分頁sql,只能把分頁sql的select和table、order都放到代碼程序中進行拼接,那么我們的思路二就來了。

  思路二:1、接着我們思路一第一步之后的往下走

      2、代碼中拼接分頁查詢sql;看代碼如下:

pagesb.AppendFormat("SELECT {0} from {1} where 1=1 {2} order by {3} limit (@pageNum - 1) * @pageSize,@pageSize;",
selectField, tableName, whereSql, orderField);

  結論:還是走不通啊啊啊啊啊啊!從錯誤日志中查看(@pageNum - 1) * @pageSize,@pageSize這些值都已經傳入了,但是就是報錯;內容如下:Message: 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 '(1-1)*20, 20' at line 12.

最后發現limit(,) 函數參數內不能進行計算,只能傳入值,並且是int類型。

  小結:我們就把(@pageNum - 1) * @pageSize的計算放到了代碼中。最后代碼如下:

int pageindex = (pageNum - 1) * pageSize;
paras.Add(new MySqlParameter("@pageSize", pageSize));
paras.Add(new MySqlParameter("@pageindex", pageindex));
StringBuilder pagesb = new StringBuilder();
pagesb.AppendFormat("SELECT {0} from {1} where 1=1 {2} order by {3} limit @pageindex,@pageSize;",
selectField, tableName, whereSql, orderField);

  這樣我已經成功了一半,為什么說成功了一半呢?因為有些查詢條件出現了問題,像模糊查詢,怎么都查不出來數據,即時你輸入的查詢條件是可用的。費了九牛二虎之力找到了問題所在,我們的模糊查詢盡管改成了參數化,但是我們把@XXX參數沒替換成他對應的值,因為@XXX變成了一個字符串了代碼如下:

if (!string.IsNullOrEmpty(Contact))
 {
        sbWhere.AppendFormat(" AND s.Contact LIKE '%{0}%'", @Contact");
        paras.Add(new MySqlParameter("@Contact", Contact));
}

這個問題我們用mysql的CONCAT()函數進行處理,改之后代碼如下:

if (!string.IsNullOrEmpty(Contact))
{
    sbWhere.AppendFormat(" AND s.Contact LIKE CONCAT('%',{0},'%')", "@Contact");
    paras.Add(new MySqlParameter("@Contact", Contact));
}

  這樣我們就大功告成了。雖然性能上差了很多,但是這個主要是對參數化進行的更改,其中limit(,)CONCAT() 函數的使用比較重要。

  再有就是本人也是初次接觸mysql,許多東西還需要學習。再有就是在給大家提個醒,關於IN() 函數的使用,如果有多個值1,2,3參數化類型會是string,替換值的時候會給‘1,2,3‘ 帶上單引號,自然也就找不到你需要的數據了,所以還是用or 慢慢去拼接吧。

  鄭重聲明:本博客,只是為了參數化,性能方面沒有過多的考慮。如有錯誤之處請大家海涵,望多多給予指點。

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM