http://www.mybatis.org/mybatis-3/zh/index.html 官方中文文档
以下例子基本来自官方文档。
此篇重点讲解通过注解的方式来写sql。
首先要解释下${} 与#{}的区别,
sql:select * from tb_user where user_name = ${userName}
参数:userName = 'xiaoming'
执行后:select * from tb_user where user_id = ?
sql:select * from tb_user where user_name = ${userName}
参数:userName = 'xiaoming' (String)
执行后:select * from tb_user where user_id = 1
可以看出,#{} 传参可以防止sql注入攻击。那什么是sql注入攻击?
拿第二句(${})可能会被攻击的句子, 假如攻击者模拟了个 String userName = "xiaoming or 1 = 1",
sql 语句变成了:select * from tb_user where user_name = xiaoming or 1 = 1
执行后的结果就是把tb_user表里面的数据全部取出来了!
==============================================================
跳过xml方式的sql。
注解提供了一种简单的方式来实现简单映射语句,而不会引入大量的开销。
这个例子展示了如何使用 @SelectKey 注解来在插入前读取数据库序列的值:
@Insert("insert into table3 (id, name) values(#{nameId}, #{name})")
@SelectKey(statement="call next value for TestSequence", keyProperty="nameId", before=true, resultType=int.class)
int insertTable3(Name name);
这个例子展示了如何使用 @SelectKey 注解来在插入后读取数据库识别列的值:
@Insert("insert into table2 (name) values(#{name})")
@SelectKey(statement="call identity()", keyProperty="nameId", before=false, resultType=int.class)
int insertTable2(Name name);
大多数对数据库的操作基本是 查询操作,下面先看下查询出来的每个字段都独自处理的方式。
@Results(id = "userResult", value = {
@Result(property = "id", column = "uid", id = true),
@Result(property = "firstName", column = "first_name"),
@Result(property = "lastName", column = "last_name")
})
@Select("select * from users where id = #{id}")
User getUserById(Integer id);
@Results(id = "companyResults")
@ConstructorArgs({
@Arg(property = "id", column = "cid", id = true),
@Arg(property = "name", column = "name")
})
@Select("select * from company where id = #{id}")
Company getCompanyById(Integer id);
可以看到,我们使用@Results的方式,需要对取出来的每个字段,可以遇见如果我们的mapper接口几个方法就要占据了大幅度的篇幅。个人感觉这对维护一个系统并不是很好的选择。特殊的需求可以特殊处理。
单一参数使用 @SqlProvider 注解的情况
@SelectProvider(type = UserSqlBuilder.class, method = "buildGetUsersByName")
List<User> getUsersByName(String name);
class UserSqlBuilder {
public static String buildGetUsersByName(final String name) {
return new SQL(){{
SELECT("*");
FROM("users");
if (name != null) {
WHERE("name like #{value} || '%'");
}
ORDER_BY("id");
}}.toString();
}
}
mybatis提供了一种 SQL类的方式来定义我们需要的sql语句。sql构建器的好处就上假设我们就使用字符串拼接的方式,字符串拼接的方式最容易犯错误的地方就是 +号的左右有没有加空格。
当然你也可以写sql语句。http://www.mybatis.org/mybatis-3/zh/statement-builders.html 官方第一个例子。
多参数使用 @SqlProvider 注解
@SelectProvider(type = UserSqlBuilder.class, method = "buildGetUsersByName")
List<User> getUsersByName(
@Param("name") String name, @Param("orderByColumn") String orderByColumn);
class UserSqlBuilder {
// If not use @Param, you should be define same arguments with mapper method
// 如果你没用@Param,你需要定义mapper上方法的参数
public static String buildGetUsersByName(
final String name, final String orderByColumn) {
return new SQL(){{
SELECT("*");
FROM("users");
WHERE("name like #{name} || '%'");
ORDER_BY(orderByColumn);
}}.toString();
}
// If use @Param, you can define only arguments to be used
//如果你使用了@Param,你可以只定义你需要用到的参数。
public static String buildGetUsersByName(@Param("orderByColumn") final String orderByColumn) {
return new SQL(){{
SELECT("*");
FROM("users");
WHERE("name like #{name} || '%'");
ORDER_BY(orderByColumn);
}}.toString();
}
}
@SelectProvider 我们仔细看下,我们需要给它提供2个必要的参数,type就是你sql语句写的类,method 就是你需要调用的sql的那个方法名。
官方给的例子里面都是返回实体类,假设我们需要返回别的类,假设是对user表和role表进行一个联合查询,我需要user的名字和role的名称。那我定义了一个UserRoleDto,那要返回的时候该去找它的哪个映射?
这时候就要用到@ResultMap这个注解。
我们可以看到
它只有一个value属性。很明确,这个就是让我们去定位我们该用哪个ResultMap。
我们的ResultMap当然是定义在mapper.xml文件下的。
我们先看下mapper接口处:
我们看下SelectProvide用到的方法。
最后是我们ResultMap的定位,我们需要把它看成两部分。
先是红框框起来的,这个表示我们resultMap所在xml的namespace,后面就是我们resulMap的id