映射器是MyBatis最复杂且最重要的组件。它由一个接口加上XML文件(或者注解)组成。在映射器中可以配置参数、各类的sql语句、存储过程、缓存、级联等复杂的内容,并且通过简易的映射规则映射到指定的POJO或者其他对象上,映射器能有效消除JDBC底层代码。
2.1 概述
主要元素有8个:insert, select, update, delete, sql, resultMap, cache, cache-ref。
2.2 select——查询语句
主要元素有:id, parameterType, resultType, resultMap。
2.2.1 简单应用
id与Mapper的全限定名联合成为一个唯一的标识,用于标识这条SQL。
parameterType表示这条SQL返回接受的参数类型,可以是MyBatis系统定义或自定义的别名,也可以是类的全限定名。
resultType表示这条SQL返回的结果类型。
#{firstName}是通过Mapper接口传入的参数。
则可以知道,只有这条SQL还不够,我们需要提供一个接口,给类似Service类进行调用访问,比如此接口方法可定义为:
public Integer countUserByFirstName(String firstName);
2.2.2 自动映射和驼峰映射
MyBatis提供自动映射功能,在默认情况下自动映射是开启的,使用它的好处在于能有效减少大量的映射配置,从而减少工作量。
在setting元素中有两个可以配置的选项autoMappingBehavior和mapUnderscoreToCamelCase,它们是控制自动映射和驼峰映射的开关。
如果系统都严格按照驼峰命名法(比如,数据库字段为role_name,则POJO属性名为roleName),那么只要在配置项把mapUnderscoreToCamelCase设置为true即可。
MyBatis会严格按照驼峰命名的方式做自动映射,只是这样会要求数据字段和POJO的属性名严格对应,降低了灵活性,这也是实际工作中需要考虑的问题。
2.2.3 传递多个参数
1.使用map接口传递参数
例如,可以把接口方法定义为:
public List
map几乎适合所有场景,但用的不多。原因有二:首先,map是一个键值对应的集合,使用者要通过阅读它的键,才能明了作用;其次,使用map不能限定其传递的数据类型,因此业务性质不强,可读性差,使用者要读懂代码才能知道需要传递什么参数。
2.使用注解
可以通过@Param(org.apache.ibatis.annotation.Param),可以通过它去定义映射器的参数名称,使用它可以得到更好的可读性,例如,可以把接口方法定义为:
public List
3.通过Java Bean
例如,可以把接口方法定义为:
public List
2.2.4 使用resultMap映射结果集
2.2.5 分页参数RowBounds
2.3 insert元素——插入语句
2.3.1 主键回填
JDBC中的Statement对象在执行插入SQL后,可以通过getGeneratedKeys方法获得数据库生成的主键(需要数据库驱动主持),这样便能达到获取主键的功能。在insert语句中有一个开关属性useGeneratedKeys,用来控制是否打开这个功能,它的默认值是false。当打开了这个开关,还要配置其属性keyProperty或keyColumn,告诉系统把主键放入哪个主键中,如果存在多个主键,就要用逗号把他们隔开。
useGeneratedKeys代表采用JDBC的Statement对象的getGeneratedKeys返回主键,而keyProperty则代表将用哪个POJO的属性去匹配这个主键,说明它会用数据库生成主键去赋值给这个POJO,测试主键回填的结果。
2.4 update元素和delete元素
与上雷同
2.5 resultMap元素
resultMap的作用是定义映射规则、级联的更新、定制类型转化器等。resultMap定义的主要是一个结果集的映射关系,也就是SQL到Java Bean的映射关系定义,它也支持级联等特性。只是MyBatis现有版本只支持resultMap查询,不支持更新或保存,更不支持级联的更新、删除和修改。
2.5.1 resultMap元素构成
resultMap元素的子元素如下:
2.5.2 使用POJO存储结果集
使用map方式就意味着可读性的丢失,POJO是最常用的方式。一方面可以使用自动映射,正如使用resultType属性一样,但是有时候需要更为复杂的映射或级联,这个时候还可以使用select语句的resultMap属性配置映射集合,只是使用前要配置类似的resultMap。示例如下:
resultMap元素的属性id代表这个resultMap的标识,type代表这需要映射的POJO,这里可以使用MyBatis定义好的类的别名,也可以使用自定义的类的全限定名。
在映射关系中,id元素表示这个对象的主键,property代表着POJO的属性名称,column表示数据库sql的列名。
2.6 级联
级联是一个数据库实体概念。比如角色就需要存在用户与之对应,这样就有角色用户表,一个角色可能有多个用户,这就是一对多级联;还有一对一的级联,比如身份证和公民是一对一的关系。在MyBatis中还有一种鉴别器的级联,它是一种可以选择具体实现类的级联,比如要查找雇员及其体检表的信息,但是雇员有性别之分,而根据性别不同,其体检表的项目也会不一样。
级联不是必须的,级联的好处是获取关键数据是否便捷,但级联过多会增加系统的复杂度,同时降低系统的性能,所以当级联的层数超过3层时,就不要使用级联了,因为这样会造成多个对象关联,导致系统的耦合、复杂和难以维护。
2.6.1 延迟加载
MyBatis支持延迟加载,我们希望一次性把常用的级联数据提供SQL直接查询出来,而对于那些不常用的级联数据不要取出,等待用时才取出,对这些数据可采用延时加载的功能。
MyBatis的settings配置中存在两个元素可以配置级联。
lazyLoadingEnabled是一个开关,决定开不开启延迟加载,默认值为false,则不开启延迟加载。
而aggressiveLazyLoading的默认值,在3.4.2版本之后变为false,之前是true。
2.7 缓存
在MyBatis中允许使用缓存,缓存一般放在可高速读写的存储器上。比如服务器的内存,它能能够有效提高系统的性能,因为数据库在大部分场景下是把存储在磁盘上的数据索引出来。索引磁盘是一个较为缓慢的过程,读取内存或者高速缓存处理器的速度要比读取磁盘快得多,但是它们空间有限,所以一般只会把那些常用且命中率高的数据缓存起来,以便将来使用。
2.7.1 一级缓存和二级缓存
一级缓存是在SqlSession上的缓存,二级缓存只在SqlSessionFactory上的缓存。默认也就是没有任何配置的情况下,MyBatis会开启一级缓存,这个缓存不需要POJO对象可序列化(实现java.io.Serializable接口)。