代码背景:某公司使用 MyBatis 作为持久层框架,登录功能如下:
Java 接口代码:
public interface UserMapper {
User findByUsernameAndPassword(@Param("username") String username,
@Param("password") String password);
}
XML 配置(UserMapper.xml)如下:
<select id="findByUsernameAndPassword" parameterType="map" resultType="User">
SELECT * FROM users
WHERE username = '${username}'
AND password = '${password}'
</select>
先来分析一下java接口代码
UserMapper
是MyBatis约定俗称的,MyBatis
数据的访问接口都叫xxxxUser
说明这里是要操作User
表
User findByUsernameAndPassword(...)
User:这是返回值类型,说明这个方法会返回一个 User 类型的 Java 对象。
int add(int a, int b); // 返回 int
String getName(); // 返回 String
void logout(); // 返回 void(表示没有返回值)
User findByUsername(...); // 返回 User
findByUsernameAndPassword:方法名称。看名字就知道,它表示"根据用户名和密码查找用户"。
@Param("username") String username,
@Param("password") String password
这是传入的两个参数
告诉 MyBatis:我这个 String username 参数,在 SQL 里要叫 username。
如果不添加@Param("username")
那么在编译成.class文件后,这个方法里面的参数会变成
(String arg0, String arg1)
那么Mybatis就读不到你叫他username,password
现在再来分析XML文件
<select id="findByUsernameAndPassword" parameterType="map" resultType="User">
<select id =xxxxx>
要把这个 SQL 查询语句,绑定到 Java 接口里的 findByUsernameAndPassword() 方法上,等你调用这个方法的时候,我就执行这个 SQL,并把查到的数据返回回去。parameterType="map"
表示传入的方法是表示方法传入的是 Map 类型(键值对)
resultType="User"
查询结果将映射成 User 类型的 Java 对象
接下来就是sql语法了,这里需要关注
${}
和#{}
#{} 是安全的参数占位符(预编译/参数化)
${} 是直接字符串拼接(不安全,容易 SQL 注入)
但是如果必须使用${}时,就需要添加白名单
比方说:动态排序
如果写成
select * from users order by #{}
数据库就会报错 Unknown column '?'
因为数据库只会把值
参数化,而不会把结构
参数化!