我们之前已经介绍 MyBatis配置 ,这次就来看一看我们的映射文件,我们MyBatis是一个半自动的ORM框架,我们需要写一些的SQL语句,SQL语句主要写在我们的Mapper文件之间,这里可以把我们数据库中一行行的数据转换成我们的JavaBean对象。
在我们的Mapper文件中,第一个主要就是书写 Sql 语句,第二个就是我们数据库信息和我们的 POJO 类的映射。
我们这里就来 select 为例来查看一下其中可以设置哪些参数:
元素 | 说明 | 备注 |
---|---|---|
id | 它和Mapper的命名空间组合起来是唯一的,提供给MyBatis调用 | 如果命名空间和id组合起来不唯一,会抛出异常 |
parameterType | 传入参数的类型;可以给出类全名,也可以给出类别名,使用别名必须是MyBatis内部定义或自定义的; 基本数据类型: int , String , long , date(不只是sql.date 还是 util.date) 复杂数据类型:类 和 Map |
可以选择JavaBean, Map等复杂的参数类型传递给SQL |
resultType | 从这条语句中返回的期望类型的类的完全限定名或别名。 注意如果是集合情形,那应该是集合可以包含的类型,而不能是集合本身。 使用 resultType 或 resultMap,但不能同时使用 定义类的全路径,在允许自动匹配的情况下,结果集将通过JavaBean的规范映射; 或者定义为int,double,float等参数… 也可以使用别名,但是要符合别名规范,不能和resultMap同时使用。 |
它是我们常用的参数之一,比如我们总计总条数就可以把它的值设为int |
resultMap | 外部 resultMap 的命名引用。使用 resultMap 或 resultType, 但不能同时使用;它是映射集的引用,将执行强大的映射功能,我们可以使用resultType或者resultMap其中的一个, resultMap可以给予我们自定义映射规则的机会 | 它是MyBatis最复杂的元素,可以配置映射规则,级联, typeHandler等 |
flushCache | 它的作用是在调用SQL后,是否要求MyBatis清空之前查询的本地缓存和二级缓存 | true/false,默认为false |
useCache | 启动二级缓存开关,是否要求MyBatis将此次结果缓存 | true/false,默认为true |
timeout | 设置超时时间,超时之后抛出异常,秒 | 默认值为数据库厂商提供的JDBC驱动所设置的秒数 |
fetchSize | 获取记录的总条数设定 | 默认值是数据库厂商提供的JDBC驱动所设的条数 |
其中 id 就是和我们的Mapper接口一一对应的,parameterType 就是我们传入参数的Java类型,至于我们的 resultType 和 resultMap 我们不能同时使用,那么它们之间有什么区别呢?
我们先来看看 resultType ,resultType 是自动映射的,它引入的是我们类的全路径或者是类的别名(别名使用 typeAliases 进行设置。),它映射的规则就是数据库字段和我们的类字段同名,不同名则无法映射赋值,我们可以使用 as 给字段名起个别名。
另外如果数据库使用下划线,类使用驼峰,一种也是可以使用 as 别名,另外就是我们全局进行配置,就是 settings 下的 mapUnderscoreToCamelCase 设置为 true 即可。
但是在 MyBatis配置 中的 settings 配置中我们提到过我们是可以关闭我们的自动映射的,若我们将其设置为 NONE ,这样我们就无法自动映射了。
如下,我们还是使用之前博客说的例子,再不开启自动映射的情况下,我们的取出的结果为 null 。
那么当我们的自动映射关闭后,我们可以使用 resultMap 来解决,这里就需要我们手动的来一一设置数据库字段和POJO类字段的对应管理。
上述我们谈到了 resultType 和 resultMap 的区别及用法,我们发现采用 resultType 自动映射是比较方便的,那么是不是我们就是比较推荐 resultType ?答案不是的,在阿里巴巴开发手册中,明确要求我们使用 resultMap 进行配置映射关系,以便以后若是我们的类字段发现了变化,或者数据库字段发现了变化,可以很好地维护。
既然阿里都推荐使用 resultMap 的话,那我们就来看一看我们 resultMap 的属性吧
属性 | 描述 |
---|---|
id | 当前命名空间中的一个唯一标识,用于标识一个result map |
type | 类的完全限定名, 或者一个类型别名 |
autoMapping | 如果设置这个属性, MyBatis将会为这个 ResultMap 开启或者关闭自动映射。这个属性会覆盖全局的属性 autoMappingBehavior。默认值为: unset。 |
至于 autoMapping 我们一般不进行配置,因为我们既然使用了 resultMap 就是准备手动的进行一一映射,我们为什么要在 resultMap 里面进行字段的自动映射呢,那还不如直接使用 resultType 方便。
我们看完 resultMap 元素后,我们再来看看其常用的子元素
属性 | 描述 |
---|---|
constructor | 用于在实例化类时,注入结果到构造方法中 |
constructor_idArg | ID 参数;标记出作为 ID 的结果可以帮助提高整体性能 |
constructor_arg | 将被注入到构造方法的一个普通结果 |
id | 一个 ID 结果;标记出作为 ID 的结果可以帮助提高整体性能 |
result | 注入到字段或 JavaBean 属性的普通结果 |
association | 一个复杂类型的关联;许多结果将包装成这种类型 嵌套结果映射 – 关联可以指定为一个 resultMap 元素,或者引用一个 |
collection | 一个复杂类型的集合 嵌套结果映射 – 集合可以指定为一个 resultMap 元素,或者引用一个 |
discriminator | 使用结果值来决定使用哪个 resultMap |
discriminator_case | 基于某些值的结果映射 嵌套结果映射 – 一个 case 也是一个映射它本身的结果,因此可以包含很多相同的元素,或者它可以参照一个外部的 resultMap |
属性 | 描述 |
---|---|
property | 映射到列结果的字段或属性。如果用来匹配的 JavaBeans 存在给定名字的属性,那么它将会被使用。否则 MyBatis将会寻找给定名称 property 的字段。 无论是哪一种情形,你都可以使用通常的点式分隔形式进行复杂属性导航。 |
column | 数据库中的列名,或者是列的别名。一般情况下,这和 传递给 resultSet.getString(columnName) 方法的参数一样。 |
javaType | 一个 Java 类的完全限定名,或一个类型别名(参考上面内建类型别名 的列表) 。如果你映射到一个 JavaBean,MyBatis通常可以断定类型。 然而,如果你映射到的是 HashMap,那么你应该明确地指定 javaType 来保证期望的行为。 |
jdbcType | JDBC 类型,所支持的 JDBC 类型参见这个表格之后的“支持的 JDBC 类型”。 只需要在可能执行插入、更新和删除的允许空值的列上指定 JDBC 类型。这是 JDBC 的要求而非 MyBatis 的要求。如果你直接面向 JDBC 编程,你需要对可能为 null 的值指定这个类型。 |
typeHandler | 使用这个属性,你可以覆盖默 认的类型处理器。这个属性值是一个类型处理 器实现类的完全限定名,或者是类型别名。 |
(ps:column字段不是指定特定表中的指定,它可能指多个表,是针对 sql 语句而言的。)
上表中大部分我们都已经使用过了,这里我们在补充一个 constructor 的用法。
这个是有什么用呢?就是为了解决我们需要映射的 POJO 没有对应的无参构造方法
我们都知道一个类要是没有任何构造方法,它默认会有一个无参的构造方法,但是我们如果设置了一个有参构造方法,那么它就不会默认为我们提供无参构造方法了,所以我们我们在代码规范中,一般要求添加了有参构造方法,就必须提供无参构造方法。
下面我们为我们 resultMap 映射的类只提供一个有参构造方法
运行测试代码,程序就报错了,因为它默认会调用我们的无参构造方法,这里我的 User 类不存在无参构造方法
这里我们需要多提一句,就是我们的 resultMap 映射时,不是必须要求 Setter 方法的,要是没有 Setter 方法能不能映射成功呢?
也是可以的,我们 MyBatis 在映射时,不是简单的利用我们的反射来完成的,它如果不存在 Setter 方法,那么我们在反射过程中会进行处理,生成了相应的Setter/Getter方法,最后来完成我们字段的映射过程。