mybatis中的#和$的区别

先来一段比较难懂的官话(大佬看的),哈哈哈:

经常碰到这样的面试题目:#{}和${}的区别是什么?

正确的答案是:#{}是预编译处理,${}是字符串替换。

(1)mybatis在处理#{}时,会将sql中的#{}替换为?号,调用PreparedStatement的set方法来赋值。

(2)mybatis在处理${}时,就是把${}替换成变量的值。

(3)使用#{}可以有效的防止SQL注入,提高系统安全性。原因在于:预编译机制。预编译完成之后,SQL的结构已经固定,即便用户输入非法参数,也不会对SQL的结构产生影响,从而避免了潜在的安全风险。

(4)预编译是提前对SQL语句进行预编译,而其后注入的参数将不会再进行SQL编译。我们知道,SQL注入是发生在编译的过程中,因为恶意注入了某些特殊字符,最后被编译成了恶意的执行操作。而预编译机制则可以很好的防止SQL注入。

下面是菜鸟看的:

对于(1)和(2)的理解:

1、使用${}方式传入的参数,mybatis不会对它进行特殊处理,而使用#{}传进来的参数,mybatis默认会将其当成字符串。可能在赋值给如id=#{id}和id=${id}看不出多大区别,但是作为表名或字段参数时可以明显看出,可以看看下面的例子:
假设传入的参数为表名test

selec * from #{table};

解析后是:

select * from "test"; 

select * from ${table};

解析后是:

select * from test;

很明显,前者多了字符串的引号,会失败,后者正常查询会成功;
所以对于传入分组(order)字段或者排序字段(order),应使用${},避免出现order  by "id" 等情况。

对于第(3)(4)句话的理解:

2、#和$在预编译处理中是不一样的。#类似jdbc中的PreparedStatement,对于传入的参数,在预处理阶段会使用?代替,比如:

select * from student where id = ?;

待真正查询的时候即在数据库管理系统中(DBMS)才会代入参数。
而${}则是简单的替换,如下:

select * from student where id = 2;

总结:

1、能使用#{}的地方应尽量使用#{}

2、传参区别:

#{}表示一个占位符号,通过#{}可以实现preparedStatement向占位符中设置值,自动进行java类型和jdbc类型转换。#{}可以有效防止sql注入。 #{}可以接收简单类型值或pojo属性值。 如果parameterType传输单个简单类型值(8大原始值类型),#{}括号中可以是value或其它名称。如果parameterType传输pojo类型,#{}括号中是pojo中字段的名称。

 

${}表示拼接sql串,通过${}可以将parameterType 传入的内容拼接在sql中且不进行jdbc类型转换, ${}可以接收简单类型值或pojo属性值,如果parameterType传输单个简单类型值,${}括号中只能是value。如果parameterType传输pojo类型,${}括号中是pojo中字段的名称。

3、${}导致sql注入的例子:

${ } 在预编译之前已经被变量替换了,这会存在 sql 注入问题。例如,如下的 sql:
 

select * from ${tableName} where name = #{name}  


假如,我们的参数 tableName 为 user; delete user; --,那么 SQL 动态解析阶段之后,预编译之前的 sql 将变为:

select * from user; delete user; -- where name = ?;  


-- 之后的语句将作为注释,不起作用,因此本来的一条查询语句偷偷的包含了一个删除表数据的 SQL。
 

上一篇:创建Mybatis步骤


下一篇:POJO与 JavaBean 的区别