群里有个小伙伴问了个我觉得很有意思的问题,在此记录下
问:order by #{date}与order by date有什么区别
理解:
#{}为占位符,比如你date这个变量值为 name desc 那么打印的sql就是 order by name desc
${}为拼接字符串,比如你date这个变量值为 name desc 那么打印的sql就是 order by "name desc",sql执行报错(错误的理解)
order by date 就是根据date这个字段排序
demo测试:
使用#{}
@Override
public List<ExcelUser> selectUser(String var) {
return userMapper.selectUser("name desc");
}
<select id="selectUser" resultType="com.excel.model.ExcelUser">
select * from test_excel order by #{var}
</select>
SQL打印:
Preparing: select * from test_excel order by ?
Parameters: name desc(String)
Total: 4
结果:
执行成功
使用${}
@Override
public List<ExcelUser> selectUser(String var) {
return userMapper.selectUser("name desc");
}
<select id="selectUser" resultType="com.excel.model.ExcelUser">
select * from test_excel order by #{var}
</select>
SQL打印:
Preparing: select * from test_excel order by name desc
Parameters:
Total: 4
结果:
执行成功
var为一个具体的值
@Override
public List<ExcelUser> selectUser(String var) {
return userMapper.selectUser("2021001");
}
<select id="selectUser" resultType="com.excel.model.ExcelUser">
select * from test_excel order by #{var}
</select>
报错信息:
java.sql.SQLSyntaxErrorException: Unknown column '2021001' in 'order clause'
未知列:'2021001'
原因:
order by 是根据字段去排序的。从表中未查询到'2021001'这个列,所以报错
${} 与 #{} 区别
1、 处理方式不同
${} 是将参数直接替换到 SQL 中
<select id="selectUser" resultType="com.excel.model.ExcelUser">
select * from test_excel order by #{var}
</select>
SQL打印:
Preparing: select * from test_excel order by name desc
Parameters:
Total: 4
#{} 则是使用占位符的方式,用预处理的方式来执行业务
<select id="selectUser" resultType="com.excel.model.ExcelUser">
select * from test_excel order by #{var}
</select>
SQL打印:
Preparing: select * from test_excel order by ?
Parameters: name desc(String)
Total: 4
2、 取值范围不同
MyBatis既可以获取执行SQL时插入的请求参数,也可以从主配置文件加载的配置文件中获取配置参数。
#{}
只能获取请求参数的值,无法获取配置参数。
${}
在MyBatis初始化时能获取配置参数,如果没有,执行时再获取请求参数。
3、安全性不同
${} 会出现 SQL 注入的问题, #{} 因为是预处理方式,不会存在安全问题
使用场景:登录
使用${}登录:
<select id="login" resultType="com.example.demo.model.UserInfo">
select * from userinfo where name='${name}' and password='${password}'
</select>
@Test
void login() {
UserInfo userInfo = userMapper.login( "java", "java" );
system.out.println(userInfo);
}
SQL打印:
Preparing: select * from userinfo where name='java' and password='java'
结果:
登陆成功
然而使用这种方式,在我们不知道密码的情况下却可以使用sql注入的方式使其登陆成功
<select id="login" resultType="com.example.demo.model.UserInfo">
select * from userinfo where name='${name}' and password='${password}'
</select>
@Test
void login() {
UserInfo userInfo = userMapper.login( "java", "'or 1='1" );
system.out.println(userInfo);
}
SQL打印:
Preparing:select * from userinfo where name='java' and password='' or 1=1
结果:
登陆成功
使用#{}登录:
<select id="login" resultType="com.example.demo.model.UserInfo">
select * from userinfo where name = #{name} and password = #{password}
</select>
@Test
void login() {
UserInfo userInfo = userMapper.login( "java", "'or 1='1" );
system.out.println(userInfo);
}
Sql打印:
Preparing: select * from userinfo where name=? and password=?
Parameters: java(String), ' or 1='1(String)
结果:
登陆失败