Mabatis详解之#{}与${}的区别

其实看了很多篇文章,有说加单引号的也有说加双引号的,整的还挺蒙,我觉得这都不是关键,下面说一下我的理解,有错误请及时纠正。

#{}:是预编译处理

这就告诉 MyBatis 创建一个预处理语句(PreparedStatement)参数,在 JDBC 中,这样的一个参数在 SQL 中会由一个“?”(占位符)来标识,并被传递到一个新的预处理语句中,就像这样:会将sql中的#{}替换为?号,调用PreparedStatement的set方法来赋值;

// 近似的 JDBC 代码,非 MyBatis 代码...
String selectPerson = "SELECT * FROM PERSON WHERE ID=?";
PreparedStatement ps = conn.prepareStatement(selectPerson);
ps.setInt(1,id);

 也就是说不管你传的参数是什么,就是一个删除数据的语句,数据库也只会将这个参数赋值给问号那个位置,将这个值赋给id,假如xxx是name 传如的参数为delete table (就是一个例子,假如能成功执行)那么如果使用#{}就是将name的值变成delete table,而${}就会真正的将你的表删除。

 String sql = "select * from table where xxx = ? and yyy = ?";

${}:字符串替换

${}会直接取出变量对应的值,进行sql语句拼接。

默认情况下,使用 #{} 参数语法时,MyBatis 会创建 PreparedStatement 参数占位符,并通过占位符安全地设置参数(就像使用 ? 一样)。 这样做更安全,更迅速,通常也是首选做法,不过有时你就是想直接在 SQL 语句中直接插入一个不转义的字符串。 比如 ORDER BY 子句,这时候你可以:

ORDER BY ${columnName}

这样,MyBatis 就不会修改或转义该字符串了。

当 SQL 语句中的元数据(如表名或列名)是动态生成的时候,字符串替换将会非常有用。 举个例子,如果你想 select 一个表任意一列的数据时,不需要这样写:

@Select("select * from user where id = #{id}")
User findById(@Param("id") long id);

@Select("select * from user where name = #{name}")
User findByName(@Param("name") String name);

@Select("select * from user where email = #{email}")
User findByEmail(@Param("email") String email);

而是可以只写这样一个方法:

@Select("select * from user where ${column} = #{value}")
User findByColumn(@Param("column") String column, @Param("value") String value);

其中 ${column} 会被直接替换,而 #{value} 会使用 ? 预处理。 这样,就能完成同样的任务:

User userOfId1 = userMapper.findByColumn("id", 1L);
User userOfNameKid = userMapper.findByColumn("name", "kid");
User userOfEmail = userMapper.findByColumn("email", "noone@nowhere.com");

这种方式也同样适用于替换表名的情况。

提示 用这种方式接受用户的输入,并用作语句参数是不安全的,会导致潜在的 SQL 注入攻击。因此,要么不允许用户输入这些字段,要么自行转义并检验这些参数。sql注入攻击就是指如果参数column的值为" id where id=xxx order byxxx;"这个值就会直接传进sql语句进行编译,原来的where语句因为后边有;就会被舍弃,那么如果写个delete你的数据就会丢失,很危险。总的来讲就是尽量使用#{}。

上一篇:HDU 1150 Machine Schedule (二分图最小点覆盖)


下一篇:python 图像处理(12):基本形态学滤波