1. 前言
设计初期的 MyBatis 是一个 XML 驱动的框架。配置信息是基于 XML 的,映射语句也是定义在 XML 中的。
在 MyBatis 3 中,我们提供了其它的配置方式。MyBatis 3 构建在全面且强大的基于 Java 语言的配置 API 之上。它是 XML 和注解配置的基础。注解提供了一种简单且低成本的方式来实现简单的映射语句。
不幸的是,Java 注解的表达能力和灵活性十分有限。尽管我们花了很多时间在调查、设计和试验上,但最强大的 MyBatis 映射并不能用注解来构建——我们真没开玩笑。而 C# 属性就没有这些限制,因此 MyBatis.NET 的配置会比 XML 有更大的选择余地。
虽说如此,基于 Java 注解的配置还是有它的好处的。
2. 常用注解
2.1 @CacheNamespace
@CacheNamespace作用于类,是XML配置<\cache>的等价替换,为给定的命名空间(比如类)配置缓存。
示例:
@CacheNamespace(implementation = CustomCache.class, properties = {
@Property(name = "host", value = "${mybatis.cache.host}"),
@Property(name = "port", value = "${mybatis.cache.port}"),
@Property(name = "name", value = "usersCache")
})
public interface UserMapper {
// ...
}
2.2 @CacheNamespaceRef
@CacheNamespaceRef作用于类,是XML配置<\cacheRef>的等价替换,引用另外一个命名空间的缓存以供使用。
注意,即使共享相同的全限定类名,在 XML 映射文件中声明的缓存仍被识别为一个独立的命名空间。
示例:
@CacheNamespaceRef(UserMapper.class)
public interface AdminUserMapper {
// ...
}
注意: 如果你使用了这个注解,你应设置 value 或者 name 属性的其中一个。value 属性用于指定能够表示该命名空间的 Java 类型(命名空间名就是该 Java 类型的全限定类名),name 属性则直接指定了命名空间的名字。
2.3 @Property
@Property是XML配置<\property>的等价替换,指定参数值或占位符,该占位符能被 mybatis-config.xml 内的配置属性替换。
2.4 @ConstructorArgs
@ConstructorArgs作用于方法,是XML配置<\constructor>的等价替换,收集一组结果以传递给一个结果对象的构造方法。
示例:
public interface UserMapper {
@ConstructorArgs({
@Arg(column = "id", javaType = int.class, id = true),
@Arg(column = "name", javaType = String.class),
@Arg(javaType = UserEmail.class, select = "selectUserEmailById", column = "id")
})
@Select("SELECT id, name FROM users WHERE id = #{id}")
User selectById(int id);
}
2.5 @Arg
@Arg是XML配置<\arg><\idArg>的等价替换,ConstructorArgs 集合的一部分,表示一个构造方法参数。
2.6 @TypeDiscriminator
@TypeDiscriminator作用于方法,是XML配置<\discriminator>的等价替换,决定使用何种结果映射的一组取值。
示例:
public interface UserMapper {
@Select("SELECT id, name, type FROM users ORDER BY id")
@TypeDiscriminator(
column = "type",
javaType = String.class,
cases = {
@Case(value = "1", type = PremiumUser.class),
@Case(value = "2", type = GeneralUser.class),
@Case(value = "3", type = TemporaryUser.class)
}
)
List<User> selectAll();
}
2.7 @Case
@TypeDiscriminator是XML配置<\case>的等价替换,表示某个值的一个取值以及该取值对应的映射。
2.8 @Results
@Results作用于方法,是XML配置<\resultMap>的等价替换,表示一组结果映射,指定了对某个特定结果列,映射到某个属性或字段的方式。
示例:
public interface UserMapper {
@Results({
@Result(property = "id", column = "id", id = true),
@Result(property = "name", column = "name"),
@Result(property = "email" column = "id", one = @One(select = "selectUserEmailById", fetchType = FetchType.LAZY)),
@Result(property = "telephoneNumbers" column = "id", many = @Many(select = "selectAllUserTelephoneNumberById", fetchType = FetchType.LAZY))
})
@Select("SELECT id, name FROM users WHERE id = #{id}")
User selectById(int id);
}
2.9 @Result
@Result是XML配置<\result><\id>的等价替换,在列和属性或字段之间的单个结果映射。
id 属性和 XML 元素 <id> 相似,它是一个布尔值,表示该属性是否用于唯一标识和比较对象。one 属性是一个关联,和 <association> 类似,而 many 属性则是集合关联,和 <collection> 类似。这样命名是为了避免产生名称冲突。
2.10 @One
@One是XML配置<\association>的等价替换,表示复杂类型的单个属性映射。
相关配置属性:
select:指定可加载合适类型实例的映射语句(也就是映射器方法)全限定名fetchType:指定在该映射中覆盖全局配置参数columnPrefix:列前缀resultMap:用于映射单个对象的结果映射id
注意:注解 API不支持联合映射。这是由于 Java 注解不允许产生循环引用。
2.11 @Many
@Many是XML配置<\collection>的等价替换,复杂类型的集合属性映射。
属性及用法同@One。
2.12 @MapKey
@MapKey作用于方法,表示当前方法的返回值为Map,它使用对象的某个属性作为key,将对象 List 转化为 Map。
示例:
public interface UserMapper {
@MapKey("id")
@Select("SELECT id, name FROM users WHERE name LIKE #{name} || '%")
Map<Integer, User> selectByStartingWithName(String name);
}
2.13 @Options
@Options作用于方法,表示映射语句的属性,该注解允许指定大部分开关和配置选项,通常在映射语句上作为属性出现。与在注解上提供大量的属性相比,Options 注解提供了一致、清晰的方式来指定选项。
示例:
public interface UserMapper {
@Options(useGeneratedKeys = true, keyProperty = "id")
@Insert("INSERT INTO users (name) VALUES(#{name})")
boolean insert(User user);
}
2.14 @Insert @Update @Delete @Select
@Insert @Update @Delete @Select作用于方法,是XML配置<\insert><\update><\delete><\select>的等价替换,每个注解分别代表将会被执行的 SQL 语句。
示例:
public interface UserMapper {
@Select("SELECT id, name FROM users WHERE id = #{id}")
User selectById(int id);
@Delete("DELETE FROM users WHERE id = #{id}")
boolean deleteById(int id);
@Update("UPDATE users SET name = #{name} WHERE id = #{id}")
boolean update(User user);
@Insert("INSERT INTO users (id, name) VALUES(#{id}, #{name})")
void insert(User user);
}
2.15 @InsertProvider @UpdateProvider @DeleteProvider @SelectProvider
@InsertProvider @UpdateProvider @DeleteProvider @SelectProvider允许构建动态 SQL,允许你指定返回 SQL 语句的类和方法,以供运行时执行。
示例:
public interface UserMapper {
@InsertProvider(type = SqlProvider.class, method = "insert")
void insert(User user);
public static class SqlProvider {
public static String insert() {
return "INSERT INTO users (id, name) VALUES(#{id}, #{name})";
}
}
}
2.16 @Param
@Param作用于参数,如果你的映射方法接受多个参数,就可以使用这个注解自定义每个参数的名字。
否则在默认情况下,除 RowBounds 以外的参数会以 "param" 加参数位置被命名。例如 #{param1}, #{param2}。如果使用了 @Param("person"),参数就会被命名为 #{person}。
示例:
public interface UserMapper {
@Select("SELECT id, name FROM users WHERE name = #{name}")
User selectById(@Param("name") String value);
}
2.17 @SelectKey
@SelectKey作用于方法,是XML配置<\selectKey>的等价替换,功能与 <\selectKey> 标签完全一致。
示例:
public interface UserMapper {
@SelectKey(statement = "SELECT identity('users')", keyProperty = "id", before = true, resultType = int.class)
@Insert("INSERT INTO users (id, name) VALUES(#{id}, #{name})")
boolean insert(User user);
}
该注解只能在@Insert或 @InsertProvider 或 @Update 或 @UpdateProvider 标注的方法上使用,否则将会被忽略。
2.18 @ResultMap
@ResultMap作用于方法,为@Select 或者 @SelectProvider 注解指定 XML 映射中 <resultMap> 元素的 id。
这使得注解的 select 可以复用已在 XML 中定义的 ResultMap。如果标注的 select 注解中存在 @Results 或者 @ConstructorArgs 注解,这两个注解将被此注解覆盖。
示例:
public interface UserMapper {
@Select("SELECT id, name FROM users WHERE id = #{id}")
@ResultMap("userMap")
User selectById(int id);
@Select("SELECT u.id, u.name FROM users u INNER JOIN users_email ue ON u.id = ue.id WHERE ue.email = #{email}")
@ResultMap("userMap")
User selectByEmail(String email);
}
<mapper namespace="com.example.mapper.UserMapper">
<resultMap id="userMap" type="com.example.model.User">
<id property="id" column="id"/>
<result property="name" column="name"/>
<association property="email" select="selectUserEmailById" column="id" fetchType="lazy"/>
</resultMap>
</mapper>
2.19 @ResultType
@ResultType作用于方法,在使用了结果处理器的情况下,需要使用此注解。
由于此时的返回类型为 void,所以 Mybatis 需要有一种方法来判断每一行返回的对象类型。
如果在 XML 有对应的结果映射,请使用 @ResultMap 注解。如果结果类型在 XML 的 <select> 元素中指定了,就不需要使用其它注解了。否则就需要使用此注解。
比如,如果一个标注了 @Select 的方法想要使用结果处理器,那么它的返回类型必须是 void,并且必须使用这个注解(或者 @ResultMap)。这个注解仅在方法返回类型是 void 的情况下生效。
示例:
public interface UserMapper {
@ResultType(User.class)
@Select("SELECT id, name FROM users WHERE name LIKE #{name} || '%' ORDER BY id")
void collectByStartingWithName(String name, ResultHandler<User> handler);
}
2.20 @Flush
@Flush作用于方法,如果使用了这个注解,定义在 Mapper 接口中的方法就能够调用SqlSession#flushStatements() 方法。