• MyBatis中传参时为什么要用#{}


      MyBatis中传参时为什么要用#{},这个问题和MyBatis如何防止SQL注入类似。不过在解释这个问题之前,先解释一下什么是SQL注入,还有些称作注入攻击这个问题。

      SQL注入就是SQL 对传入参数的拼接。sql语句是 String类型的,如果用  +  来拼接,表示的是直接操作这个String 类型的字符串,这是改变了sql的具体内容了,如果用#{id},表示的是操作字改变里面字段的参数值。

    例如:

    • 用+拼接的: "select * from user where code="+code+ " and password="+password;

        那么code = “1233 or code=456”  password="2123":

             结果:  select * from user where code='123' or  code='456' and password=‘2123’那么这个sql的规则就乱了。

    • 用#操作的 select * from user where code=#{code} and password=#{password};

                  那么code = “1233 or code=456”  password="2123":

             结果:  select * from user where code=' 1233 or code=456 ' and password='2123'那么这个sql的规则还是老样子。

      综上所述就是会发生拼接错误!其实应该是参数传递出现的问题,#{}传递参数时,会在传递的参数上加上引号,在传递属性比如   password=? 时,可以很方便的使用#{password}。#{}传递的参数实际上是通过占位符(类似于JDBC中的?,在JDBC中会利用?去代替参数先进行编译,然后代入参数执行,这样就可以避免注入,因为注入不安全因素是发生在编译期,用占位符后就避免了这个问题)去传入到已经预编译好的SQL中去的,所以此时的SQL已经完成编译,只需要传参数就完成执行了。如:

    1 <select id =“ getBlogById ”resultType =“ Blog ”parameterType =“ int ”>
    2         SELECT id,title,author,content
    3         FROM blog
    4         WHERE id =#{id}
    5 </select>

      在这里的id传参就是使用了#{},这部分打印后会看到的SQL语句是:

    1 SELECT id,title,author,content FROM blog WHERE id =?

      就是不管输入什么参数打印出的SQL都是这样的。这是因为MyBatis的启用了预编译功能,在SQL执行前,会先将上面的SQL发送给数据库进行编译,执行时,直接使用编译好的SQL ,替换占位符“?”就可以了。因为SQL注入只能对编译过程起作用,所以这样的方式就很好地避免了SQL注入的问题。

      具体可以看底层实现:其原理就是采用了JDBC的PreparedStatement。就会将sql语句:“select id,no from user where id =?” 预先编译好,也就是SQL引擎会预先进行语法分析,产生语法树,生成执行计划,也就是说,后面你输入的参数,无论你输入的是什么,都不会影响该SQL语句的语法结构了,因为语法分析已经完成了,而语法分析主要是分析sql命令,比如select,from,where,and,or,order by等等。所以即使你后面输入了这些sql命令,也不会被当成sql命令来执行了,因为这些SQL命令的执行,必须先得通过语法分析,生成执行计划,既然语法分析已经完成,已经预编译过了,那么后面输入的参数,是绝对不可能作为SQL命令来执行的,只会被当做字符串字面值参数。所以的sql语句预编译可以防御SQL注入。而且在多次执行同一个SQL时,能够提高效率。原因是SQL已编译好,再次执行时无需再编译。

      同样的,想要避免SQL注入,只能使用上述的#{}结构,在MyBatis中,还有一种结构是${},使用该结构就不会避免注入。因为${}不会添加引号,传递的是什么就会直接放到SQL中去执行。

      简单滴说:# {}是经过预编译的,是安全的 ;$ {}是未经过预编译的,仅仅是取变量的值,是非安全的,存在SQL注入。

    参考:

    1. https://www.cnblogs.com/jy107600/p/7097983.html
    2. https://bbs.csdn.net/topics/391069848
    3. https://blog.csdn.net/weixin_40773255/article/details/80426307
    4. https://blog.csdn.net/weixin_39986856/article/details/83651847
  • 相关阅读:
    java的instanceof简单使用
    PHP中return,exit,die的区别
    C#调用Dll文件中方法的简单应用
    C#的托管和非托管的简单理解
    对象造型(引用类型转换)
    面向对象3大特性的简单理解
    css3自定义滚动条背景透明
    console.time方法与console.timeEnd方法
    IE8 input X 去掉文本框的叉叉和密码输入框的眼睛图标
    JavaSript模块规范
  • 原文地址:https://www.cnblogs.com/gjmhome/p/11296437.html
Copyright © 2020-2023  润新知