在mybatis中的$与#都是在sql中动态的传入参数。
eg:select id,name,age from student where name=#{name} 这个name是动态的,可变的
。当你传入什么样的值,就会根据你传入的值执行sql语句。
两者区别
-
就是将传入的值作为字符串的形式。用#{}传入值,sql动态解析为一个JDBC预编译语句(preparedStatement)的参数标记符,也就是说,sql语句中如果存在参数则会使用?作占位符,加了单引号,把参数默认为字符串进行处理;
"select name from user where id= ?"
- $是将传入的数据直接显示生成sql语句,sql动态解析时候不加引号,直接进行变量替换,参与SQL编译。
- 使用#可以防注入。注入就是恶意的语句拼接。
- 使用order by中需要使用$
- 在parameterType是int时,sql语句中必须是#{}。
啥叫防注入?
SQL注入起因
SQL注入是一种常见的攻击方式,攻击者或者误操作者通过表单信息或者URL输入一些异常的参数(最常用的是使用字符串连接的方式组合SQL指令),传入服务端进行SQL处理,可能会出现这样的情况
delete from app_poi where poi_id = (输入参数):
输入参数:10 or 1 = 1
SQL拼接:delete from app_poi where poi_id = (10 or 1 = 1)
执行结果:app_poi中的所有数据都会被delete
例子2:
这种问题出现的原因可能是攻击者故意为之,也可能是误操作,那么服务端该如何处理,避免这样的问题出现呢?
mybatis防注入
其实就是JDBC中的PreparedStatement类在起作用,PreparedStatement是我们很熟悉的Statement的子类,它的对象包含了编译好的SQL语句。这种“准备好”的方式不仅能提高安全性,而且在多次执行同一个SQL时,能够提高效率。原因是SQL已编译好,再次执行时无需再编译。
PreparedStatement会对SQL中输入的参数进行检测,并在SQL都是用问号来设置占位符,即只允许传入一个参数,像(10 or 1 = 1)这种明显不会被占位符所接受。
因为SQL注入只能对编译过程起作用,所以这样的方式就很好地避免了SQL注入的问题。
结论
so,#{}是经过预编译的,是安全的; 是 未 经 过 预 编 译 的 , 仅 仅 是 取 变 量 的 值 , 非 安 全 的 。 如 果 不 得 不 使 用 {}是未经过预编译的,仅仅是取变量的值,非安全的。如果不得不使用 是未经过预编译的,仅仅是取变量的值,非安全的。如果不得不使用{}那么要手工做好过滤工作。
关于注入的例子见:https://blog.csdn.net/qq_27811247/article/details/80775036