Mybatis-mapper文件中$与#的区别

Mybatis-mapper文件中$与#的区别

系列文章目录

  1. Mybatis-原理
  2. Mybatis-缓存
  3. Mybatis-mapper文件中$与#的区别
  4. Mybatis-和Hibernate对比
  5. Mybatis-collection错误去重问题
  6. Mybatis-好文推荐

0x01 #

1.1 原理

默认情况下,是用#{}会被预编译处理,会使得Mybatis创建PreparedStatement,当做占位符,参数化输入的参数,就和在sql内使用?一样。

mybatis在处理#{}时,会将sql中的#{}替换为?,调用PreparedStatement的set方法来赋值。那么,一些特殊字符就会在真正执行前被转义。

比如有以下sql:

select id,name from user where id = #{id}

那么此时会将#{id}解析为参数占位符,语句预编译为

select id,name from user where id = ?

将预编译语句传给服务器后,执行时仅将具体的参数值传递给服务器执行。

1.2 防止sql注入

也就是说,使用#{}方法可以防止拼接方式的sql注入攻击。因为SQL注入发生在SQL编译期,但是用#{}时,sql会被预编译,此后不再变化,执行sql只是传递具体的参数值来还行。

1.3 使用场景

大多数情况都是用#{},更安全和快速。

0x02 $

2.1 原理

${}只会被做简单的字符串替换处理,不会做字符串转义。

比如刚才那个sql使用$,且id参数值为23:

select id,name from user where id = ${id}

则该条语句会在动态SQL解析阶段被Mybatis解析为:

select id,name from user where id = 23

也就是说直接将该变量进行了值替换,不做任何额外处理。

2.2 使用场景

比如order by的时候,就必须使用${}:

ORDER BY ${columnName}

0x03 综合使用

我们可以综合#{}和${}进行使用,比如有如下查找语句:

@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", "[email protected]");

但需要注意的是,这样使用有被SQL注入攻击的风险,必须自己做权限控制或转义检验。

0xFF 参考文档

精讲#{}和${}的区别是什么?

Mybatis的$和#处理源码分析

mybatis-3官方文档中文版

你可能感兴趣的:(mybatis)