2019.11.01 杭州的一个面试,有问道这个问题:
讲一下Mybatis中 #{}和${}的区别?
情况一:只用 #{}
<select id="getUserByNameAndPsw" resultType="com.hotel3.model.User"> select * from USER where userName=#{userName} and userPassword =#{userPassword}; </select>
结果:
c.h.m.UserMapper.getUserByNameAndPsw : ==> Preparing: select * from USER where userName=? and userPassword =?; c.h.m.UserMapper.getUserByNameAndPsw : ==> Parameters: mww(String), 123(String) c.h.m.UserMapper.getUserByNameAndPsw : <== Total: 1
结论:
#{}会在编译期,生成两个?,作为占位符。
情况二:一个用 ${} 一个用 #{}
<select id="getUserByNameAndPsw" resultType="com.hotel3.model.User"> select * from USER where userName=${userName} and userPassword =#{userPassword}; </select>
结果:
c.h.m.UserMapper.getUserByNameAndPsw : ==> Preparing: select * from USER where userName=mww and userPassword =?; c.h.m.UserMapper.getUserByNameAndPsw : ==> Parameters: 123(String)
结论:很显然 ${} 是直接拼成字符串的 ,#{} 是生成 ? 占位符的。
而且 因为 userName:mww 是字符串,所以 这种写法显然也是错误的。
会爆出如下错误:
### Error querying database. Cause: java.sql.SQLSyntaxErrorException: Unknown column ‘mww‘ in ‘where clause‘
所以正确的写法是这样的:为字符串字段加上单引号 ‘ ‘
<select id="getUserByNameAndPsw" resultType="com.hotel3.model.User"> select * from USER where userName=‘${userName}‘ and userPassword =#{userPassword}; </select>
结果:
c.h.m.UserMapper.getUserByNameAndPsw : ==> Preparing: select * from USER where userName=‘mww‘ and userPassword =?; c.h.m.UserMapper.getUserByNameAndPsw : ==> Parameters: 123(String) c.h.m.UserMapper.getUserByNameAndPsw : <== Total: 1
结论:显然这种写法是正确的,从这里可以看出,编译期 ${} 是直接把参数拼结到SQL中,运行时,就只传入了一个 #{} 修饰的参数。
${}的这种写法还有一个安全隐患,那就是 SQL注入。
情况三: ${} SQL注入:
<select id="getUserByNameAndPsw" resultType="com.hotel3.model.User"> select * from USER where userName=‘${userName}‘ and userPassword =#{userPassword}; </select>
结果:
c.h.m.UserMapper.getUserByNameAndPsw : ==> Preparing: select * from USER where userName=‘‘ OR 1=1 OR ‘‘ and userPassword =?; c.h.m.UserMapper.getUserByNameAndPsw : ==> Parameters: 65787682342367(String) c.h.m.UserMapper.getUserByNameAndPsw : <== Total: 2
结论:只要我们在 ${} 输入 ‘ OR 1=1 OR ‘ 无论后面的密码输入什么都可以,查询到数据,这种情况就是SQL输入。
在这种用法中, #{} 显然比 ${} 用法更好。那 ${} 为什么经常在 Mybatis 使用那。
${}正确用法:
同时传入字段名和字段值:
User u=userService.getUserByNameAndPsw("userName,userType,userPassword",userName,userPassword);
SQL: select ${arg0} from USER
<select id="getUserByNameAndPsw" resultType="com.hotel3.model.User"> select ${arg0} from USER where userName=#{userName} and userPassword =#{userPassword}; </select>
结果:
c.h.m.UserMapper.getUserByNameAndPsw : ==> Preparing: select userName,userType,userPassword from USER where userName=? and userPassword =?; c.h.m.UserMapper.getUserByNameAndPsw : ==> Parameters: mww(String), 123(String) c.h.m.UserMapper.getUserByNameAndPsw : <== Total: 1
结论:
待续。。。。
原文:https://www.cnblogs.com/mww-NOTCOPY/p/11777187.html