zoukankan      html  css  js  c++  java
  • (记录)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 慢慢去拼接吧。

      郑重声明:本博客,只是为了参数化,性能方面没有过多的考虑。如有错误之处请大家海涵,望多多给予指点。

    俗话说:好记性不如烂笔头,对于本人来说,写博客是为了总结,巩固自己的所学。
    文章中如有错误,不足之处,望指出,本人会及时改正。有想法的朋友可以及时评论,相互学习和进步。
    非常感谢您的阅读。如对你有用,喜欢的文章“推荐一下”吧!欢迎转载和收藏!
  • 相关阅读:
    FastJson的简单使用
    一些没用过的方法的学习
    Windows系统激活
    mysql数据库运行性能检查脚本
    基于windows 的Apache HTTP Server的一次小安装
    MySQL、Oracle批量插入、更新批量inisert、update
    IDEA中右键没有“Subversion”相关目录解决方法
    关于spring boot项目启动报错问题
    我的2016
    用intellij IDEA 编写时,无编程提示问题
  • 原文地址:https://www.cnblogs.com/lizejia/p/6732207.html
Copyright © 2011-2022 走看看