其实看了很多篇文章,有说加单引号的也有说加双引号的,整的还挺蒙,我觉得这都不是关键,下面说一下我的理解,有错误请及时纠正。
#{}:是预编译处理
这就告诉 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你的数据就会丢失,很危险。总的来讲就是尽量使用#{}。