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注入。
参考:
- https://www.cnblogs.com/jy107600/p/7097983.html
- https://bbs.csdn.net/topics/391069848
- https://blog.csdn.net/weixin_40773255/article/details/80426307
- https://blog.csdn.net/weixin_39986856/article/details/83651847