·你需要先明确“SQL注入”的概念
-SQL语句中存在一些参数,在实际运行时,传入的参数值可能改变语义,导致执行的S QL语句与预期的(设计的)不同
·需要先明确“预编译”的概念
-编译:无论是哪种语言的源代码,在执行之前,都必须经过编译
-编译之前,会进行相关的检查,例如:词法分析、语义分析,仅当能够通过这
些检查才可以编译
-预编译:在尚未确定某些值的情况下执行编译!
-尽管值是未知的,但是其语法结构是合法的,并不影响编译器理解这条语句
-例如:select*fromuserwhereid=?
-值只影响执行结果,并不影响编译
-SQL语句一旦经过预编译,将不存在SQL注入风险
-编译之前已经确定语义,无论参数值是什么样的,都不会改变语义
·Mybatis的#{}占位符(SQL语句占位符,会进行预编译,防止SQL注入)
-Mybatis在处理SQL语句中的#{}占位符时,会将其替换成问号,并通过预编译的
方式(使用PreparedStatement)进行处理的
-只可以表示某个值,不可以表示SQL语句中的某个片段
-是预编译的
-在不考虑参数的值是多少的情况下,SQL语句必须是合法的不需要考虑参数值的 数据类型
-例如:不需要在字符串类型的值的两侧添加单引号
-代入值之前已经预编译,语义已经确定,则不存在SQL注入风险
·Mybatis的${}占位符(不会对传入的值进行预编译)
-Mybatis在处理SQL语句中的${}占位符时,是单纯的把占位符替换成参数值,再进行后 续的 处理的
-可以表示SQL语句中的任何片段,只需要保证最终拼接出来的SQL语句是合法的
-需要考虑参数值的数据类型
-例如:需要在字符串类型的值的两侧添加单引号
-需要考虑SQL注入的风险
-参数的值可能改变语义
-可以在执行SQL语句之前进行检查
总结:
·相同之处:
-都是写在SQL语句中,都是用于表示参数值的
·不同之处:
-#{}格式的占位符将被替换为问号,是通过预编译进行处理的,所以,使用#{}只能表示 某 个值,而不能表示SQL语句中的某个片段,同时,由于是预编译的,所以不需要考虑 参数值的数据类型问题,也没有SQL注入风险
-${}格式的占位符将直接被替换为参数值,所以,只要保证最终得到的SQL语句是合法 的,它可以表示SQL语句中的任何片段,但是,需要考虑参数值中涉及的各值的数据类 型,例如字符串类型的值需要在两侧添加单引号,并且,由于在编译SQL语句之前就已 经将参数值添加到SQL语句中了,需要考虑SQL注入的风险
·实际使用原则:
-因为使用${}格式的占位符有SQL注入风险,如果执行数据访问之前没有对参数进行 完整的检验,是不安全的,并且,还要考虑各值的数据类型问题,相对麻烦,所以, 一般使用#{}格式的占位符。