映射器注解
因为最初设计时,MyBatis 是一个 XML 驱动的框架。配置信息是基于 XML 的,而且 映射语句也是定义在 XML 中的。而到了 MyBatis 3,有新的可用的选择了。MyBatis 3 构建 在基于全面而且强大的 Java 配置 API 之上。这个配置 API 是基于 XML 的 MyBatis 配置的 基础,也是新的基于注解配置的基础。注解提供了一种简单的方式来实现简单映射语句,而 不会引入大量的开销。
注意 不幸的是,Java 注解限制了它们的表现和灵活。尽管很多时间都花调查,设计和 实验上,最强大的 MyBatis 映射不能用注解来构建,那并不可笑。C#属性(做示例)就没 有这些限制,因此 MyBatis.NET 将会比 XML 有更丰富的选择。也就是说,基于 Java 注解 的配置离不开它的特性。
注解有下面这些:
注解 | 目标 | 相对应的 XML | 描述 |
---|---|---|---|
@CacheNamespace | 类 | <cache> | 为给定的命名空间 (比如类) 配置缓存。 属性:implemetation,eviction, flushInterval,size,readWrite,blocking 和 properties。 |
@Property | N/A | <property> | Specifies the property value or placeholder(can replace by configuration properties that defined at the mybatis-config.xml). Attributes: name, value. (Available on MyBatis 3.4.2+) |
@CacheNamespaceRef | 类 | <cacheRef> | 参照另外一个命名空间的缓存来使用。属性:value, name。 If you use this annotation, you should be specified either value or name attribute.For the value attribute specify a java type indicating the namespace(the namespace name become a FQCN of specified java type), and for the name attribute(this attribute is available since 3.4.2) specify a name indicating the namespace. |
@ConstructorArgs | 方法 | <constructor> | 收集一组结果传递给一个劫夺对象的 构造方法。属性:value,是形式参数 的数组。 |
@Arg | N/A |
| 单 独 的 构 造 方 法 参 数 , 是 ConstructorArgs 集合的一部分。属性: id,column,javaType,typeHandler。 id 属性是布尔值, 来标识用于比较的属 性,和<idArg>XML 元素相似。 |
@TypeDiscriminator | 方法 | <discriminator> | 一组实例值被用来决定结果映射的表 现。 属性: column, javaType, jdbcType, typeHandler,cases。 cases 属性就是实 例的数组。 |
@Case | N/A | <case> | 单独实例的值和它对应的映射。属性: value,type,results。Results 属性是结 果数组,因此这个注解和实际的 ResultMap 很相似,由下面的 Results 注解指定。 |
@Results | 方法 | <resultMap> | 结果映射的列表, 包含了一个特别结果 列如何被映射到属性或字段的详情。 属 性:value, id。value 属性是 Result 注解的数组。这个id的属性是结果映射的名称。 |
@Result | N/A |
| 在列和属性或字段之间的单独结果映 射。属 性:id,column, property, javaType ,jdbcType ,type Handler, one,many。id 属性是一个布尔值,表 示了应 该被用于比较(和在 XML 映射 中的<id>相似)的属性。one 属性是单 独 的 联 系, 和 <association> 相 似 , 而 many 属 性 是 对 集 合 而 言 的 , 和<collection>相似。 它们这样命名是为了 避免名称冲突。 |
@One | N/A | <association> | 复杂类型的单独属性值映射。属性: select,已映射语句(也就是映射器方 法)的完全限定名,它可以加载合适类 型的实例。注意:联合映射在注解 API 中是不支持的。 这是因为 Java 注解的 限制,不允许循环引用。 fetchType会覆盖全局的配置参数lazyLoadingEnabled。 |
@Many | N/A | <collection> | 映射到复杂类型的集合属性。属性:select,已映射语句(也就是映射器方法)的全限定名, 它可以加载合适类型的实例的集合,fetchType会覆盖全局的配置参数lazyLoadingEnabled。 注意联合映射在注解 API中是不支持的。这是因为 Java 注解的限制,不允许循环引用 |
@MapKey | 方法 | 复 杂 类 型 的 集合 属 性 映射 。 属 性 : select,是映射语句(也就是映射器方 法)的完全限定名, 它可以加载合适类 型的一组实例。注意:联合映射在Java 注解中是不支持的。 这是因为 Java 注 解的限制,不允许循环引用。 | |
@Options | 方法 | 映射语句的属性 | 这个注解提供访问交换和配置选项的 宽广范围, 它们通常在映射语句上作为 属性出现。 而不是将每条语句注解变复 杂,Options 注解提供连贯清晰的方式 来访问它们。 属性:useCache=true , flushCache=FlushCachePolicy.DEFAULT , resultSetType=FORWARD_ONLY , statementType=PREPARED , fetchSize=-1 , , timeout=-1 useGeneratedKeys=false , keyProperty=”id” , keyColumn=”” , resultSets=””。 理解 Java 注解是很 重要的,因为没有办法来指定“null” 作为值。 因此,一旦你使用了 Options 注解,语句就受所有默认值的支配。要 注意什么样的默认值来避免不期望的行为。 |
| 方法 |
| 这些注解中的每一个代表了执行的真 实 SQL。 它们每一个都使用字符串数组 (或单独的字符串)。 如果传递的是字 符串数组, 它们由每个分隔它们的单独 空间串联起来。 这就当用 Java 代码构 建 SQL 时避免了“丢失空间”的问题。然而,如果你喜欢,也欢迎你串联单独 的字符串。属性:value, 这是字符串 数组用来组成单独的 SQL 语句。 |
| 方法 |
| 这些可选的 SQL 注解允许你指定一个 类名和一个方法在执行时来返回运行 允许创建动态 的 SQL。 基于执行的映射语句, MyBatis 会实例化这个类,然后执行由 provider 指定的方法. You can pass objects that passed to arguments of a mapper method,"Mapper interface type" and "Mapper method" via the ProviderContext(available since MyBatis 3.4.5 or later) as method argument. (In MyBatis 3.4 or later, it's allow multiple parameters) 属性: type,method。type 属性是类。method 属性是方法名。 注意: 这节之后是对 类的讨论,它可以帮助你以干净,容于阅读 的方式来构建动态 SQL。 |
@Param | Parameter | N/A | 如果你的映射器的方法需要多个参数, 这个注解可以被应用于映射器的方法 参数来给每个参数一个名字。否则,多 参数将会以它们的顺序位置来被命 名 (不包括任何 RowBounds 参数) 比如。 #{param1} , #{param2} 等 , 这 是 默 认 的 。 使 用 @Param(“person”),参数应该被命名为 #{person}。 |
@SelectKey | 方法 | <selectKey> | 该注解复制了<selectKey>的功能,用在注解了@Insert, @InsertProvider, @Update or @UpdateProvider的方法上。 在其他方法上将被忽略。如果你指定了一个@SelectKey注解,然后Mybatis将忽略任何生成的key属性通过设置@Options,或者配置属性。 属性: statement是要执行的sql语句的字符串数组, keyProperty是需要更新为新值的参数对象属性, before可以是true或 者false分别代表sql语句应该在执行insert之前或者之后, resultType是keyProperty的Java类型, statementType是语句的类型, 取Statement, PreparedStatement和CallableStatement对应的STATEMENT, PREPARED或者CALLABLE其中一个, 默认是PREPARED。 |
@ResultMap | 方法 | N/A | 这个注解给@Select或者@SelectProvider提供在XML映射中的<resultMap>的id。 这使得注解的select可以复用那些定义在XML中的 ResultMap。 如果同一select注解中还存在@Results或者@ConstructorArgs,那么这两个注解将被此注解覆盖。 |
@ResultType | Method | N/A | 当使用结果处理器时启用此注解。这种情况下,返回类型为void,所以Mybatis必须有一种方式决定对象的类型,用于构造每行数据。 如果有XML的结果映射,使用@ResultMap注解。 如果结果类型在XML的<select>节点中指定了,就不需要其他的注解了。 其他情况下则使用此注解。比如,如果@Select注解在一个方法上将使用结果处理器,返回类型必须是void并且这个注解 (或者@ResultMap)是必须的。 这个注解将被忽略除非返回类型是void。 |
@Flush | 方法 | N/A | 如果这个注解使用了,它将调用定义在Mapper接口中的SqlSession#flushStatements()方法。(Mybatis 3.3或者以上) |
映射申明样例
这个例子展示了如何使用 @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);
这个例子展示了如何使用@Flush注解去调用SqlSession#flushStatements():
@Flush List<BatchResult> flush();
这些例子展示了如何通过指定@Result的id属性来命名结果集:
@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);
这个例子展示了单一参数使用@SqlProvider:
@SelectProvider(type = UserSqlBuilder.class, method = "buildGetUsersByName") List<User> getUsersByName(String name); class UserSqlBuilder { public String buildGetUsersByName(final String name) { return new SQL(){{ SELECT("*"); FROM("users"); if (name != null) { WHERE("name like #{value} || '%'"); } ORDER_BY("id"); }}.toString(); } }
这个列子展示了多参数使用@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 public 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 public String buildGetUsersByName(@Param("orderByColumn") final String orderByColumn) { return new SQL(){{ SELECT("*"); FROM("users"); WHERE("name like #{name} || '%'"); ORDER_BY(orderByColumn); }}.toString(); } }