【转】Mybatis中 #{}和${}的区别

添加链接描述
2019.11.01 杭州的一个面试,有问道这个问题:

讲一下Mybatis中 #{}和${}的区别?

部分内容涉及到 MySQL的预编译

情况一:只用 #{}

select * from USER where userName=#{userName} and userPassword =#{userPassword};

 结果:
==> Preparing: select * from USER where userName=? and userPassword =?;
> Parameters: mww(String), 123(String)
<
Total: 1
 结论:
    #{}会在预编译期,生成两个 ?,作为占位符。

情况二:一个用 KaTeX parse error: Expected 'EOF', got '#' at position 8: {} 一个用 #̲{} <select id…{userName} and userPassword =#{userPassword};

  结果:
==> Preparing: select * from USER where userName=mww and userPassword =?;
==> Parameters: 123(String)
  结论:很显然 ${} 是直接拼成字符串的 ,#{} 是生成 ?占位符的。
     而且 因为 userName:mww 是字符串,所以 这种写法显然也是错误的。

会报出如下错误:

Error querying database. Cause: java.sql.SQLSyntaxErrorException: Unknown column ‘mww’ in ‘where clause’

所以正确的写法是这样的:为字符串字段加上单引号 ’ ’

select * from USER where userName='${userName}' and userPassword =#{userPassword};   结果:

==> Preparing: select * from USER where userName=‘mww’ and userPassword =?;
> Parameters: 123(String)
<
Total: 1
  结论:显然这种写法是正确的,从这里可以看出,预编译期 ${} 是直接把参数拼结到SQL中,

运行时,就只传入了一个 #{} 修饰的参数。

${}的这种写法还有一个安全隐患,那就是 SQL注入。

情况三: S Q L 注 入 : < s e l e c t i d = " g e t U s e r B y N a m e A n d P s w " r e s u l t T y p e = " c o m . h o t e l 3. m o d e l . U s e r " > s e l e c t ∗ f r o m U S E R w h e r e u s e r N a m e = ′ {} SQL注入: <select id="getUserByNameAndPsw" resultType="com.hotel3.model.User"> select * from USER where userName=' SQL<selectid="getUserByNameAndPsw"resultType="com.hotel3.model.User">selectfromUSERwhereuserName={userName}’ and userPassword =#{userPassword};

  结果:
==> Preparing: select * from USER where userName=’’ OR 1=1 OR ‘’ and userPassword =?;
> Parameters: 65787682342367(String)
<
Total: 2
  结论:只要我们在 ${} 输入 ’ OR 1=1 OR ’ 无论后面的密码输入什么都可以,查询到数据,这种情况就是SQL注入。

情况四:#{} 防止SQL注入

select * from USER where userName=#{userName} and userPassword =#{userPassword};

  结果:

==> Preparing: select * from USER where userName=? and userPassword =?;
> Parameters: ’ OR 1=1 OR '(String), 123(String)
<
Total: 0
  结论:上面预编译SQL的参数已经由占位符 { ?} 代替,所以传入的 ’ OR 1=1 OR ’ 只会作为 userName字段的值,

而不会拼入执行的SQL。这样就达到了防止SQL注入的目的。

在这种用法中, #{} 显然比 ${} 用法更好。

那 ${} 为什么经常在 Mybatis 使用那?

${}正确用法(个人见解):
  1、同时传入一个字段名和字段值:
User u=userService.getUserByNameAndPsw(“userName,userType,userPassword”,userName,userPassword);
    SQL: select ${arg0} from USER

select ${arg0} from USER where userName=#{userName} and userPassword =#{userPassword};     结果:

==> Preparing: select userName,userType,userPassword from USER where userName=? and userPassword =?;
> Parameters: mww(String), 123(String)
<
Total: 1
    结论:

生成了我们想要SQL语句 :select userName,userType,userPassword from USER。。。。

2、传入两个字段名和字段值:
User u=userService.getUserByNameAndPsw(“userName,userType,userPassword”,userName,userName,userPassword);
    SQL: select ${arg0} from USER where ${arg1}=#{userName}

select ${arg0} from USER where ${arg1}=#{userName} and userPassword =#{userPassword};     结果:

==> Preparing: select userName,userType,userPassword from USER where userName=? and userPassword =?;
> Parameters: mww(String), 123(String)
<
Total: 1
    结论:

按照传参的顺序匹配 SQL 中的 a r g 0 , {arg0}, arg0{arg1}。。。

生成我们想要的代码,但这个方式会使Mybatis 的 Mapper 文件可读性变差,

如果不看其他的代码,很难辨别 a r g 0 , {arg0} , arg0{arg1} 代表的含义。

3、使用Map传值,提高 Mapper 文件的可读性
复制代码
     Map map =new HashMap();
map.put(“selectValues”,“userName,userType,userPassword”);
map.put(“userNamefieId”,“userName”);
map.put(“userName”,userName);
map.put(“userPassword”,userPassword);
User u=userService.getUserByNameAndPsw(map);
复制代码
    Mapper 文件的 xml

select ${selectValues} from USER where ${userNamefieId}=#{userName} and userPassword =#{userPassword};     结果:

==> Preparing: select userName,userType,userPassword from USER where userName=? and userPassword =?;
> Parameters: mww(String), 123(String)
<
Total: 1
    结论:

结果和arg0、arg1的传值方式相同,但 Mapper 文件的 xml 中的SQL语句可以

通过对 map 中 key 值命名提高可读性。

注:以上SQL,均为预编期生成的SQL。

注2:${} 每次传值不同 SQL 语句不同,可以灵活生成 SQL,

但每次都需要进行预编译,对效率会有影响,至于要不要使用 ${}还要具体情况具体分析。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值