mybatis使用总结
介绍
首个类持久性框架
分为JDBC(原始SQL)和Hibernate(ORM)简化绝大部分JDBC代码,
手工设置参数和获取结果
灵活,使用者能够完全控制SQL,支持高级映射
防止sql注入
说明:在MyBatis中,使用XML文件或注释来进行配置和映射,将接口和Java POJO(普通的旧Java对象)映射到数据库记录
xml例子
映射器界面
@Mapper
public interface UserMapper {
User getById(int id);
}
** XML配置文件**
<select id="getById" resultType="org.example.User">
SELECT * FROM user WHERE id = #{id}
</select
注释示例
@Mapper
public interface UserMapper {
@Select("SELECT * FROM user WHERE id= #{id}")
User getById(@Param("id") int id);
}
可以看到,使用者需要自己编写SQL语句,因此当使用不当时,会导致注入问题
与使用JDBC不同的是,MyBatis使用#{}和${}来进行参数值替换
使用#{}语法时,MyBatis会自动生成PreparedStatement,使用参数绑定(?)的方式来设置值,
上述两个示例等价的JDBC查询代码如下:
String sql = "SELECT * FROM users WHERE id = ?";
PreparedStatement ps = connection.prepareStatement(sql);
ps.setInt(1, id);
因此#{}可以有效防止SQL注入,详细可参考http://www.mybatis.org/mybatis-3/sqlmap-xml.html 字符串替换部分
而使用${}语法时,MyBatis会直接注入原始字符串,即相当于分段字符串,因此会导致SQL注入,如
<select id="getByName" resultType="org.example.User">
SELECT * FROM user WHERE name = '${name}' limit 1
</select>
名称估计’ or ‘1’='1,实际执行的语句为
SELECT * FROM user WHERE name = '' or '1'='1' limit 1
因此建议尽量使用#{},但有些时候,如按语句排序,使用#{}会导致错误,如
ORDER BY #{sortBy}
sortBy参数估计name,替换后会成为
ORDER BY "name"
即以字符串“ name”来排序,而不是按名称排序,详细可参考https://stackoverflow.com/a/32996866/6467552。
这种情况就需要使用 ${}
ORDER BY ${sortBy}
使用了${}后,使用者需要自行过滤输入,方法有:
代码层使用白名单的方式,限制sortBy允许的值,如只能为name,email变量,异常情况则设置为替换值name
在XML配置文件中,使用if标签来进行判断
Mapper接口方法
List<User> getUserListSortBy(@Param("sortBy") String sortBy);
<select id="getUserListSortBy" resultType="org.example.User">
SELECT * FROM user
<if test="sortBy == 'name' or sortBy == 'email'">
order by ${sortBy}
</if>
</select>
因为Mybatis不支持else,需要替换值的情况,可以使用 choose (when, otherwise)
<select id="getUserListSortBy" resultType="org.example.User">
SELECT * FROM user
<choose>
<when test="sortBy == 'name' or sortBy == 'email'">
order by ${sortBy}
</when>
<otherwise>
order by name
</otherwise>
</choose>
</select>
like语句
在代码层,在参数值两边加上%,然后再使用#{}
使用bind标签来构造新参数,然后再使用#{}
Mapper接口方法
List<User> getUserListLike(@Param("name") String name);
xml配置文件
<select id="getUserListLike" resultType="org.example.User">
<bind name="pattern" value="'%' + name + '%'" />
SELECT * FROM user
WHERE name LIKE #{pattern}
</select>
语句内部的值为OGNL表达式,具体可参考http://www.mybatis.org/mybatis-3/dynamic-sql.html bind部分
使用SQL concat()函数
<select id="getUserListLikeConcat" resultType="org.example.User">
SELECT * FROM user WHERE name LIKE concat ('%', #{name}, '%')
</select>
除了注入问题之外,这里还需要对用户的输入进行过滤,永久有通配符,
否则在表中数据量中断的时候,假设用户输入为%%,会进行全表模糊查询,
严重情况下可导致DOS ,参考http://www.tothenew.com/blog/sql-wildcards-is-your-application-safe/
IN条件
使用和#{}
Mapper接口方法
List<User> getUserListIn(@Param("nameList") List<String> nameList);
<select id="selectUserIn" resultType="com.example.User">
SELECT * FROM user WHERE name in
<foreach item="name" collection="nameList"
open="(" separator="," close=")">
#{name}
</foreach>
</select>