上一篇博客的传送门:MyBatis 入门到精通(六)
本篇博客我来讲解 MyBatis 的注解方式。
什么是注解
Annotation(注解)是JDK1.5及以后版本引入的。它可以用于创建文档,跟踪代码中的依赖性,甚至执行基本编译时检查。注解是以‘@注解名’在代码中存在的,根据注解参数的个数,我们可以将注解分为:标记注解、单值注解、完整注解三类。它们都不会直接影响到程序的语义,只是作为注解(标识)存在,我们可以通过反射机制编程实现对这些元数据的访问。
MyBatis 的注解
我们前边讲解的内容都是以 XML 方式来实现的,在本章中我们使用注解的方式来改写它们。MyBatis 的注解主要有如下:
- 基本注解
- 关系注解
- 动态 SQL 操作
- 缓存注解
基本注解
@Select、@Insert、@Update和@Delete 注解
基本的增删改查的操作
@Select("select * from emp where empState=1")
List<Emp> findAllEmp();
@Select("select * from emp where empState=1 and empNo=#{empNo}")
Emp findEmpByNo(int empNo);
@Insert("insert into emp values(null,#{ename},#{job},#{mgr},now(),#{sal},#{comm},#{deptNo},1)")
void saveEmp(Emp emp);
@Update("update emp set ename=#{ename},job=#{job},mgr=#{mgr},sal=#{sal},comm=#{comm},deptNo=#{deptNo} where empno=#{empNo}")
void updateEmp(Emp emp);
@Delete("update emp set empState=0 where empno=#{empNo}")
void deleteEmp(int empNo);
@Param 注解
MyBatis 默认不能传递多个参数,如果要传递多个参数,需要通过 @Param 注解来指定参数和#{}之间的关系。
@Select("select * from emp where empState=1 limit #{start},#{size}")
List<Emp> findEmpByPage3(@Param("start") int start, @Param("size") int size);
关系注解
多表联查时,我们过去使用 ResultMap 标签来手动对结果集进行设置,在注解中也可以对结果集进行操作的方式。
@Results 和 @Result 注解
这两个注解都是手动对结果集进行映射的。
@Select("select * from emp where empState=1 and empNo=#{empNo}")
@Results(id = "map1", value = {
@Result(column = "mgr", property = "mgr"),
@Result(column = "ename", property = "job")
})
Emp findEmpByNo(int empNo);
@Result 的相关属性:
- column:数据库的列名
- property:需要装配的属性名
- one:需要使用的@One注解(@Result(one=@One)()))
- many:需要使用的@Many注解(@Result(many=@many)()))
@One 和 @Many 注解
这两个注解是一对多和多对一注解。
// 获取员工信息,并通过@one获取到部门信息
@Select("select * from emp where empState=1 and empNo=#{empNo}")
@Results(id = "map2",value = {
@Result(column = "empNo",property = "empNo",id = true),
@Result(column = "ename",property = "ename",javaType = String.class),
@Result(column = "deptNo",property = "dept",javaType = Dept.class,
one = @One(select = "com.dailyblue.java.mapper.DeptMapper.findDeptByNo")
)
})
Emp findEmpByNo(int empNo);
// 获取部门,并通过@Many获取员工信息
@Select("select * from dept where deptNo=#{deptNo}")
@Results(id = "deptMap1",value = {
@Result(column = "deptNo",property = "deptNo",id = true),
@Result(column = "loc",property = "dname"),
@Result(column = "dname",property = "loc"),
@Result(column = "deptNo",property = "empSet",javaType = Set.class,
many = @Many(select = "com.dailyblue.java.mapper.EmpMapper.findAllEmpByDeptNo"))
})
Dept findDeptByNo(int deptNo);
两个注解的相关属性:
- select:指定用来多表查询的 sqlmapper。
- fetchType:会覆盖全局的配置参数 lazyLoadingEnabled 。
@ResultMap 注解
通过这个注解来使用其他方法中定义好的@Results。这里的 deptMap1 是上一个案例中 @Results 的 id 值。
@Select("select * from dept where deptNo=#{deptNo}")
@ResultMap("deptMap1")
Dept findDeptByNo(int deptNo);
动态 SQL 操作
我们一般使用 <script></script> 将 SQL 语句包裹住,就可以使用动态 SQL 了。
缓存注解
@CacheNamespace 注解
作用于mapper接口上面,是用来实现二级缓存的。
@CacheNamespace(blocking = true)
public interface EmpMapper{
}
blocking 属性默认值为 false,在该属性为 true 的情况下 Mybatis 采用的缓存装饰器为 BlockingCache。大意是说在执行同一 SQL 查询时当前线程会先去获取锁,其他执行该查询的 SQL 线程只能等待当前线程查询完成后才能继续查询而不是直接命中数据库。
MyBatis 注解 API
注解 | 使用对象 | XML 等价形式 | 描述 |
---|---|---|---|
@CacheNamespace | 类 | <cache> | 为给定的命名空间(比如类)配置缓存。属性:implemetation、eviction、flushInterval、size、readWrite、blocking、properties。 |
@Property | N/A | <property> | 指定参数值或占位符(placeholder)(该占位符能被 mybatis-config.xml 内的配置属性替换)。属性:name、value。(仅在 MyBatis 3.4.2 以上可用) |
@CacheNamespaceRef | 类 | <cacheRef> | 引用另外一个命名空间的缓存以供使用。注意,即使共享相同的全限定类名,在 XML 映射文件中声明的缓存仍被识别为一个独立的命名空间。属性:value、name。如果你使用了这个注解,你应设置 value 或者 name 属性的其中一个。value 属性用于指定能够表示该命名空间的 Java 类型(命名空间名就是该 Java 类型的全限定类名),name 属性(这个属性仅在 MyBatis 3.4.2 以上可用)则直接指定了命名空间的名字。 |
@ConstructorArgs | 方法 | <constructor> | 收集一组结果以传递给一个结果对象的构造方法。属性:value,它是一个 Arg 数组。 |
@Arg | N/A |
| ConstructorArgs 集合的一部分,代表一个构造方法参数。属性:id、column、javaType、jdbcType、typeHandler、select、resultMap。id 属性和 XML 元素 <idArg> 相似,它是一个布尔值,表示该属性是否用于唯一标识和比较对象。从版本 3.5.4 开始,该注解变为可重复注解。 |
@TypeDiscriminator | 方法 | <discriminator> | 决定使用何种结果映射的一组取值(case)。属性:column、javaType、jdbcType、typeHandler、cases。cases 属性是一个 Case 的数组。 |
@Case | N/A | <case> | 表示某个值的一个取值以及该取值对应的映射。属性:value、type、results。results 属性是一个 Results 的数组,因此这个注解实际上和 ResultMap 很相似,由下面的 Results 注解指定。 |
@Results | 方法 | <resultMap> | 一组结果映射,指定了对某个特定结果列,映射到某个属性或字段的方式。属性:value、id。value 属性是一个 Result 注解的数组。而 id 属性则是结果映射的名称。从版本 3.5.4 开始,该注解变为可重复注解。 |
@Result | N/A |
| 在列和属性或字段之间的单个结果映射。属性:id、column、javaType、jdbcType、typeHandler、one、many。id 属性和 XML 元素 <id> 相似,它是一个布尔值,表示该属性是否用于唯一标识和比较对象。one 属性是一个关联,和 <association> 类似,而 many 属性则是集合关联,和 <collection> 类似。这样命名是为了避免产生名称冲突。 |
@One | N/A | <association> | 复杂类型的单个属性映射。属性:select,指定可加载合适类型实例的映射语句(也就是映射器方法)全限定名;fetchType,指定在该映射中覆盖全局配置参数 lazyLoadingEnabled。提示 注解 API 不支持联合映射。这是由于 Java 注解不允许产生循环引用。 |
@Many | N/A | <collection> | 复杂类型的集合属性映射。属性:select,指定可加载合适类型实例集合的映射语句(也就是映射器方法)全限定名;fetchType,指定在该映射中覆盖全局配置参数 lazyLoadingEnabled。提示 注解 API 不支持联合映射。这是由于 Java 注解不允许产生循环引用。 |
@MapKey | 方法 | 供返回值为 Map 的方法使用的注解。它使用对象的某个属性作为 key,将对象 List 转化为 Map。属性:value,指定作为 Map 的 key 值的对象属性名。 | |
@Options | 方法 | 映射语句的属性 | 该注解允许你指定大部分开关和配置选项,它们通常在映射语句上作为属性出现。与在注解上提供大量的属性相比,Options 注解提供了一致、清晰的方式来指定选项。属性:useCache=true、flushCache=FlushCachePolicy.DEFAULT、resultSetType=DEFAULT、statementType=PREPARED、fetchSize=-1、timeout=-1、useGeneratedKeys=false、keyProperty=""、keyColumn=""、resultSets=""。注意,Java 注解无法指定 null 值。因此,一旦你使用了 Options 注解,你的语句就会被上述属性的默认值所影响。要注意避免默认值带来的非预期行为。 注意:keyColumn 属性只在某些数据库中有效(如 Oracle、PostgreSQL 等)。要了解更多关于 keyColumn 和 keyProperty 可选值信息,请查看“insert, update 和 delete”一节。 |
| 方法 |
| 每个注解分别代表将会被执行的 SQL 语句。它们用字符串数组(或单个字符串)作为参数。如果传递的是字符串数组,字符串数组会被连接成单个完整的字符串,每个字符串之间加入一个空格。这有效地避免了用 Java 代码构建 SQL 语句时产生的“丢失空格”问题。当然,你也可以提前手动连接好字符串。属性:value,指定用来组成单个 SQL 语句的字符串数组。 |
| 方法 |
| 允许构建动态 SQL。这些备选的 SQL 注解允许你指定返回 SQL 语句的类和方法,以供运行时执行。(从 MyBatis 3.4.6 开始,可以使用 CharSequence 代替 String 来作为返回类型)。当执行映射语句时,MyBatis 会实例化注解指定的类,并调用注解指定的方法。你可以通过 ProviderContext 传递映射方法接收到的参数、"Mapper interface type" 和 "Mapper method"(仅在 MyBatis 3.4.5 以上支持)作为参数。(MyBatis 3.4 以上支持传入多个参数)属性:type、method。type 属性用于指定类名。method 用于指定该类的方法名(从版本 3.5.1 开始,可以省略 method 属性,MyBatis 将会使用 ProviderMethodResolver 接口解析方法的具体实现。如果解析失败,MyBatis 将会使用名为 provideSql 的降级实现)。提示 接下来的“SQL 语句构建器”一章将会讨论该话题,以帮助你以更清晰、更便于阅读的方式构建动态 SQL。 |
@Param | 参数 | N/A | 如果你的映射方法接受多个参数,就可以使用这个注解自定义每个参数的名字。否则在默认情况下,除 RowBounds 以外的参数会以 "param" 加参数位置被命名。例如 #{param1}, #{param2}。如果使用了 @Param("person"),参数就会被命名为 #{person}。 |
@SelectKey | 方法 | <selectKey> | 这个注解的功能与 <selectKey> 标签完全一致。该注解只能在 @Insert 或 @InsertProvider 或 @Update 或 @UpdateProvider 标注的方法上使用,否则将会被忽略。如果标注了 @SelectKey 注解,MyBatis 将会忽略掉由 @Options 注解所设置的生成主键或设置(configuration)属性。属性:statement 以字符串数组形式指定将会被执行的 SQL 语句,keyProperty 指定作为参数传入的对象对应属性的名称,该属性将会更新成新的值,before 可以指定为 true 或 false 以指明 SQL 语句应被在插入语句的之前还是之后执行。resultType 则指定 keyProperty 的 Java 类型。statementType 则用于选择语句类型,可以选择 STATEMENT、PREPARED 或 CALLABLE 之一,它们分别对应于 Statement、PreparedStatement 和 CallableStatement。默认值是 PREPARED。 |
@ResultMap | 方法 | N/A | 这个注解为 @Select 或者 @SelectProvider 注解指定 XML 映射中 <resultMap> 元素的 id。这使得注解的 select 可以复用已在 XML 中定义的 ResultMap。如果标注的 select 注解中存在 @Results 或者 @ConstructorArgs 注解,这两个注解将被此注解覆盖。 |
@ResultType | 方法 | N/A | 在使用了结果处理器的情况下,需要使用此注解。由于此时的返回类型为 void,所以 Mybatis 需要有一种方法来判断每一行返回的对象类型。如果在 XML 有对应的结果映射,请使用 @ResultMap 注解。如果结果类型在 XML 的 <select> 元素中指定了,就不需要使用其它注解了。否则就需要使用此注解。比如,如果一个标注了 @Select 的方法想要使用结果处理器,那么它的返回类型必须是 void,并且必须使用这个注解(或者 @ResultMap)。这个注解仅在方法返回类型是 void 的情况下生效。 |
@Flush | 方法 | N/A | 如果使用了这个注解,定义在 Mapper 接口中的方法就能够调用 SqlSession#flushStatements() 方法。(Mybatis 3.3 以上可用) |